gpt4 book ai didi

node.js - 如何使用Node.js提供图片

转载 作者:太空宇宙 更新时间:2023-11-04 01:42:47 26 4
gpt4 key购买 nike

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

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时,我显然没有得到徽标。

服务图像需要做些什么更改。

最佳答案

2016更新

使用Express和不使用Express的示例实际有效

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

TL; DR

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


express.static
express
connect
http
net


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

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

介绍

自从问了这个问题5年多之后,通俗查询只给出了one correct answer,但是即使该回答在代码上没有问题,也似乎在接收方面存在一些问题。有人评论说,“除了如何依靠别人来完成工作外,它没有其他解释”,事实上,有多少人投票赞成该评论,这表明很多事情需要澄清。

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

回答说使用Express“除了如何依靠别人来完成工作外,并没有其他解释”,应该指出,使用http模块已经依赖于别人来完成工作。如果某人不想依靠任何人来完成工作,则至少应使用原始TCP套接字代替-我在下面的示例之一中进行了此操作。

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

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

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

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

最低功能

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


最常见文件的MIME类型
提供HTML,JS,CSS,纯文本和图像
index.html用作默认目录索引
响应错误代码以查找丢失的文件
没有路径遍历漏洞
读取文件时没有比赛条件


我在Node版本4、5、6和7上测试了每个版本。

express.static

此版本使用express.static模块的express内置中间件。

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

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中间件。服务静态文件使用流作为单个路由处理程序实现。

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

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低一个抽象级别。

此示例具有与 express版本相似的功能,但使用了稍低一些的API。

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模块,该模块是Node中HTTP的最低级别的API。

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

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套接字的最低级别的API。

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

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上发布了所有示例,并提供了更多说明。

express.staticexpressconnecthttpnet的示例:


https://github.com/rsp/node-static-http-servers


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


https://github.com/rsp/node-express-static-example


测验

可在Travis上获得测试结果:


https://travis-ci.org/rsp/node-static-http-servers


一切都在Node版本4、5、6和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 - 如何使用Node.js提供图片,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52359785/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com