如何使用Node.js提供图片 [英] How to serve an image using nodejs

查看:87
本文介绍了如何使用Node.js提供图片的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个位于public/images/logo.gif的徽标.这是我的nodejs代码.

I have a logo that is residing at the public/images/logo.gif . Here is my nodejs code.

http.createServer(function(req, res){
  res.writeHead(200, {'Content-Type': 'text/plain' });
  res.end('Hello World \n');
}).listen(8080, '127.0.0.1');

它可以工作,但是当我请求localhost:8080/logo.gif时,我显然没有得到徽标.

It works but when I request for localhost:8080/logo.gif then I obviously I don't get the logo.

提供图像我需要做些什么改变.

What changes I need to do to serve an image.

推荐答案

2016更新

使用Express和不使用Express的示例,它们实际上是有效的

这个问题已有5年历史了,但每个答案都有一些问题.

2016 Update

Examples with Express and without Express that actually work

This question is over 5 years old but every answer has some problems.

向下滚动示例以使用以下图片投放图片:

Scroll down for examples to serve an image with:

  1. express.static
  2. express
  3. connect
  4. http
  5. net
  1. express.static
  2. express
  3. connect
  4. http
  5. net

所有示例也都在GitHub上: https://github.com/rsp /node-static-http-servers

All of the examples are also on GitHub: https://github.com/rsp/node-static-http-servers

可在Travis上获得测试结果: https://travis-ci.org /rsp/node-static-http-servers

Test results are available on Travis: https://travis-ci.org/rsp/node-static-http-servers

问了这个问题超过5年之后,只有 一个正确的答案 总论,尽管该答案在代码方面没有问题,但接收似乎有些问题.有人评论说,除了如何依靠别人来完成工作外,没有什么其他解释了".事实是,有多少人投票赞成该评论,这清楚地表明了很多事情需要澄清.

After over 5 years since this question was asked there is only one correct answer by generalhenry but even though that answer has no problems with the code, it seems to have some problems with reception. It was commented that it "doesn't explain much other than how to rely on someone else to get the job done" and the fact how many people have voted this comment up clearly shows that a lot of things need clarification.

首先,对如何使用Node.js提供图像"的一个好的答案不是从头开始实现静态文件服务器且做得不好.很好的答案是使用Express这样的模块,该模块可以正确完成工作.

First of all, a good answer to "How to serve images using Node.js" is not implementing a static file server from scratch and doing it badly. A good answer is using a module like Express that does the job correctly.

关于使用Express 除了解释如何依靠别人来完成工作外,没有什么其他解释"的答案.应该注意的是,使用http模块已经依靠其他人来完成工作.如果某人不想依靠任何人来完成工作,则应该使用至少原始TCP套接字代替-我将在以下示例之一中进行此操作.

Answering comments that say that using Express "doesn't explain much other than how to rely on someone else to get the job done" it should be noted, that using the http module already relies on someone else to get the job done. If someone doesn't want to rely on anyone to get the job done then at least raw TCP sockets should be used instead - which I do in one of my examples below.

一个更严重的问题是,所有使用http模块的答案都已损坏.他们引入了竞赛条件不安全的路径解析,这将导致路径遍历漏洞阻止I/O 完全根本无法满足任何并发请求以及其他细微的问题-它们已完全被破坏为该问题的示例,但它们已经使用了http模块提供的抽象而不是使用TCP套接字,因此它们甚至不会像声称的那样从头开始做所有事情.

A more serious problem is that all of the answers here that use the http module are broken. They introduce race conditions, insecure path resolution that will lead to path traversal vulnerability, blocking I/O that will completely fail to serve any concurrent requests at all and other subtle problems - they are completely broken as examples of what the question asks about, and yet they already use the abstraction that is provided by the http module instead of using TCP sockets so they don't even do everything from scratch as they claim.

如果问题是如何从头开始实施静态文件服务器,作为学习练习",则一定要回答如何发布该问题-但即使如此,我们仍应期望它们至少是正确的.同样,并非毫无道理地假设有人想要提供图像,将来可能会提供更多图像,因此有人可能会认为编写特定的自定义静态文件服务器只能提供一个带有硬编码路径的单个文件,这是不合理的.有点短视.似乎很难想象,谁会找到有关如何提供图像的答案的人会满足于仅提供单个图像的解决方案,而不是提供任何图像的通用解决方案.

If the question was "How to implement static file server from scratch, as a learning exercise" then by all means answers how to do that should be posted - but even then we should expect them to at least be correct. Also, it is not unreasonable to assume that someone who wants to serve an image might want to serve more images in the future so one could argue that writing a specific custom static file server that can serve only one single file with hard-coded path is somewhat shortsighted. It seems hard to imagine that anyone who searches for an answer on how to serve an image would be content with a solution that serves just a single image instead of a general solution to serve any image.

简而言之,问题是如何提供图片,对此的答案是使用适当的模块以可读,可靠,安全,可靠的方式做到这一点,在使用专业Node开发的最佳实践的同时,具有可维护性和面向未来的.但是我同意,对这种答案的一个很好的补充将是显示一种手动实现相同功能的方法,但遗憾的是,到目前为止,每次尝试都失败了.这就是为什么我写了一些新的例子.

In short, the question is how to serve an image and an answer to that is to use an appropriate module to do that in a secure, preformant and reliable way that is readable, maintainable and future-proof while using the best practice of professional Node development. But I agree that a great addition to such an answer would be showing a way to implement the same functionality manually but sadly every attempt to do that has failed so far. And that is why I wrote some new examples.

简短介绍之后,这是我的五个示例,分别在5个不同的抽象级别上进行工作.

After this short introduction, here are my five examples doing the job on 5 different levels of abstraction.

每个示例都提供public目录中的文件,并支持以下最低功能:

Every example serves files from the public directory and supports the minumum functionality of:

  • 最常见文件的MIME类型
  • 提供HTML,JS,CSS,纯文本和图像
  • index.html用作默认目录索引
  • 针对缺少文件的错误代码进行响应
  • 没有路径遍历漏洞
  • 读取文件时没有比赛条件
  • MIME types for most common files
  • serves HTML, JS, CSS, plain text and images
  • serves index.html as a default directory index
  • responds with error codes for missing files
  • no path traversal vulnerabilities
  • no race conditions while reading files

我在节点版本4、5、6和7上测试了每个版本.

I tested every version on Node versions 4, 5, 6 and 7.

此版本使用 express.static <一个href ="https://expressjs.com/" rel ="noreferrer"> express 模块.

This version uses the express.static built-in middleware of the express module.

此示例具有最多的功能和最少的代码.

This example has the most functionality and the least amount of code.

var path = require('path');
var express = require('express');
var app = express();

var dir = path.join(__dirname, 'public');

app.use(express.static(dir));

app.listen(3000, function () {
    console.log('Listening on http://localhost:3000/');
});

express

此版本使用 express 模块,但没有express.static中间件.服务静态文件是使用流作为单个路由处理程序实现的.

express

This version uses the express module but without the express.static middleware. Serving static files is implemented as a single route handler using streams.

此示例具有简单的路径遍历对策,并支持一组有限的大多数常见MIME类型.

This example has simple path traversal countermeasures and supports a limited set of most common MIME types.

var path = require('path');
var express = require('express');
var app = express();
var fs = require('fs');

var dir = path.join(__dirname, 'public');

var mime = {
    html: 'text/html',
    txt: 'text/plain',
    css: 'text/css',
    gif: 'image/gif',
    jpg: 'image/jpeg',
    png: 'image/png',
    svg: 'image/svg+xml',
    js: 'application/javascript'
};

app.get('*', function (req, res) {
    var file = path.join(dir, req.path.replace(/\/$/, '/index.html'));
    if (file.indexOf(dir + path.sep) !== 0) {
        return res.status(403).end('Forbidden');
    }
    var type = mime[path.extname(file).slice(1)] || 'text/plain';
    var s = fs.createReadStream(file);
    s.on('open', function () {
        res.set('Content-Type', type);
        s.pipe(res);
    });
    s.on('error', function () {
        res.set('Content-Type', 'text/plain');
        res.status(404).end('Not found');
    });
});

app.listen(3000, function () {
    console.log('Listening on http://localhost:3000/');
});

connect

此版本使用 connect 模块,该模块的抽象级别低于express

connect

This version uses the connect module which is a one level of abstraction lower than express.

此示例具有与express版本相似的功能,但使用的杠杆级别稍低.

This example has similar functionality to the express version but using slightly lower-lever APIs.

var path = require('path');
var connect = require('connect');
var app = connect();
var fs = require('fs');

var dir = path.join(__dirname, 'public');

var mime = {
    html: 'text/html',
    txt: 'text/plain',
    css: 'text/css',
    gif: 'image/gif',
    jpg: 'image/jpeg',
    png: 'image/png',
    svg: 'image/svg+xml',
    js: 'application/javascript'
};

app.use(function (req, res) {
    var reqpath = req.url.toString().split('?')[0];
    if (req.method !== 'GET') {
        res.statusCode = 501;
        res.setHeader('Content-Type', 'text/plain');
        return res.end('Method not implemented');
    }
    var file = path.join(dir, reqpath.replace(/\/$/, '/index.html'));
    if (file.indexOf(dir + path.sep) !== 0) {
        res.statusCode = 403;
        res.setHeader('Content-Type', 'text/plain');
        return res.end('Forbidden');
    }
    var type = mime[path.extname(file).slice(1)] || 'text/plain';
    var s = fs.createReadStream(file);
    s.on('open', function () {
        res.setHeader('Content-Type', type);
        s.pipe(res);
    });
    s.on('error', function () {
        res.setHeader('Content-Type', 'text/plain');
        res.statusCode = 404;
        res.end('Not found');
    });
});

app.listen(3000, function () {
    console.log('Listening on http://localhost:3000/');
});

http

此版本使用 http 模块,该模块是节点中的HTTP.

http

This version uses the http module which is the lowest-level API for HTTP in Node.

此示例具有与connect版本相似的功能,但使用的是更低级别的API.

This example has similar functionality to the connect version but using even more lower-level APIs.

var path = require('path');
var http = require('http');
var fs = require('fs');

var dir = path.join(__dirname, 'public');

var mime = {
    html: 'text/html',
    txt: 'text/plain',
    css: 'text/css',
    gif: 'image/gif',
    jpg: 'image/jpeg',
    png: 'image/png',
    svg: 'image/svg+xml',
    js: 'application/javascript'
};

var server = http.createServer(function (req, res) {
    var reqpath = req.url.toString().split('?')[0];
    if (req.method !== 'GET') {
        res.statusCode = 501;
        res.setHeader('Content-Type', 'text/plain');
        return res.end('Method not implemented');
    }
    var file = path.join(dir, reqpath.replace(/\/$/, '/index.html'));
    if (file.indexOf(dir + path.sep) !== 0) {
        res.statusCode = 403;
        res.setHeader('Content-Type', 'text/plain');
        return res.end('Forbidden');
    }
    var type = mime[path.extname(file).slice(1)] || 'text/plain';
    var s = fs.createReadStream(file);
    s.on('open', function () {
        res.setHeader('Content-Type', type);
        s.pipe(res);
    });
    s.on('error', function () {
        res.setHeader('Content-Type', 'text/plain');
        res.statusCode = 404;
        res.end('Not found');
    });
});

server.listen(3000, function () {
    console.log('Listening on http://localhost:3000/');
});

net

此版本使用 net 模块,该模块是Node中的TCP套接字.

net

This version uses the net module which is the lowest-level API for TCP sockets in Node.

此示例具有http版本的某些功能,但是最小和不完整的HTTP协议是从头开始实现的.由于它不支持分块编码,因此在发送响应之前先将文件加载到内存中,然后再知道大小,因为先声明文件状态然后加载会引入竞争条件.

This example has some of the functionality of the http version but the minimal and incomplete HTTP protocol has been implemented from scratch. Since it doesn't support chunked encoding it loads the files into memory before serving them to know the size before sending a response because statting the files and then loading would introduce a race condition.

var path = require('path');
var net = require('net');
var fs = require('fs');

var dir = path.join(__dirname, 'public');

var mime = {
    html: 'text/html',
    txt: 'text/plain',
    css: 'text/css',
    gif: 'image/gif',
    jpg: 'image/jpeg',
    png: 'image/png',
    svg: 'image/svg+xml',
    js: 'application/javascript'
};

var server = net.createServer(function (con) {
    var input = '';
    con.on('data', function (data) {
        input += data;
        if (input.match(/\n\r?\n\r?/)) {
            var line = input.split(/\n/)[0].split(' ');
            var method = line[0], url = line[1], pro = line[2];
            var reqpath = url.toString().split('?')[0];
            if (method !== 'GET') {
                var body = 'Method not implemented';
                con.write('HTTP/1.1 501 Not Implemented\n');
                con.write('Content-Type: text/plain\n');
                con.write('Content-Length: '+body.length+'\n\n');
                con.write(body);
                con.destroy();
                return;
            }
            var file = path.join(dir, reqpath.replace(/\/$/, '/index.html'));
            if (file.indexOf(dir + path.sep) !== 0) {
                var body = 'Forbidden';
                con.write('HTTP/1.1 403 Forbidden\n');
                con.write('Content-Type: text/plain\n');
                con.write('Content-Length: '+body.length+'\n\n');
                con.write(body);
                con.destroy();
                return;
            }
            var type = mime[path.extname(file).slice(1)] || 'text/plain';
            var s = fs.readFile(file, function (err, data) {
                if (err) {
                    var body = 'Not Found';
                    con.write('HTTP/1.1 404 Not Found\n');
                    con.write('Content-Type: text/plain\n');
                    con.write('Content-Length: '+body.length+'\n\n');
                    con.write(body);
                    con.destroy();
                } else {
                    con.write('HTTP/1.1 200 OK\n');
                    con.write('Content-Type: '+type+'\n');
                    con.write('Content-Length: '+data.byteLength+'\n\n');
                    con.write(data);
                    con.destroy();
                }
            });
        }
    });
});

server.listen(3000, function () {
    console.log('Listening on http://localhost:3000/');
});

下载示例

我在GitHub上发布了所有示例,并提供了更多说明.

Download examples

I posted all of the examples on GitHub with more explanation.

具有express.staticexpressconnecthttpnet的示例:

仅使用express.static的其他项目:

Travis上提供测试结果:

Test results are available on Travis:

所有内容都在节点版本4、5、6和7上进行了测试.

Everything is tested on Node versions 4, 5, 6, and 7.

其他相关答案:

  • Failed to load resource from same directory when redirecting Javascript
  • onload js call not working with node
  • Sending whole folder content to client with express
  • Loading partials fails on the server JS
  • Node JS not serving the static image

这篇关于如何使用Node.js提供图片的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆