我有一个位于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');
Run Code Online (Sandbox Code Playgroud)
它工作,但当我要求localhost:8080/logo.gif然后我显然我没有得到徽标.
我需要做些什么来改变图像.
rsp*_*rsp 179
这个问题超过5年,但每个答案都有一些问题.
向下滚动以查看示例以提供图像:
express.staticexpressconnecthttpnet所有的例子也在GitHub上:https://github.com/rsp/node-static-http-servers
测试结果可在Travis上获得:https://travis-ci.org/rsp/node-static-http-servers
经过5年多以来,这一问题被提出,只有一个正确答案通过generalhenry但即使这个问题的答案与代码没有问题,它似乎有一些问题与接待.有人评论说,除了如何依靠别人完成工作之外,"并没有解释太多",而且有多少人投票评论这个评论清楚地表明很多事情需要澄清.
首先,对"如何使用Node.js提供图像"的一个很好的答案是没有从头开始实现静态文件服务器并且做得很糟糕.一个很好的答案是使用像Express这样的模块来正确地完成工作.
回答评论说使用Express "除了如何依赖别人完成工作之外没有其他解释"应该注意,使用该http模块已经依赖于其他人来完成工作.如果有人不想依赖任何人来完成工作,那么至少应该使用原始TCP套接字 - 我在下面的一个例子中做了这个.
一个更严重的问题是,使用该http模块的所有答案都被打破了.它们引入了竞争条件,不安全的路径解析将导致路径遍历漏洞,阻止完全无法满足任何并发请求的I/O以及其他微妙的问题 - 它们完全被打破,作为问题所要求的示例,以及然而,他们已经使用http模块提供的抽象而不是使用TCP套接字,因此他们甚至不会像他们声称的那样从头做任何事情.
如果问题是"如何从头开始实现静态文件服务器,作为一种学习练习"那么通过各种方式回答如何做到这一点应该被发布 - 但即便如此,我们也应该期望它们至少是正确的.此外,假设想要提供图像的人可能希望将来提供更多图像是不合理的,因此有人可能会认为编写一个特定的自定义静态文件服务器只能为一个具有硬编码路径的文件提供服务.有些短视.似乎很难想象任何搜索如何提供图像的答案的人都会满足于只提供单个图像的解决方案,而不是为任何图像提供服务的通用解决方案.
简而言之,问题是如何提供图像,并且答案是使用适当的模块以安全,预先形成且可靠的方式执行此操作,这种方式在使用专业节点的最佳实践时是可读的,可维护的且面向未来的发展.但是我同意这样一个答案的一个很好的补充就是显示了一种手动实现相同功能的方法,但遗憾的是,到目前为止,每次尝试这样做都失败了.这就是为什么我写了一些新的例子.
在这个简短的介绍之后,这里是我在五个不同抽象层次上完成工作的五个例子.
每个示例都提供public目录中的文件,并支持以下最小功能:
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/');
});
Run Code Online (Sandbox Code Playgroud)
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/');
});
Run Code Online (Sandbox Code Playgroud)
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/');
});
Run Code Online (Sandbox Code Playgroud)
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/');
});
Run Code Online (Sandbox Code Playgroud)
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/');
});
Run Code Online (Sandbox Code Playgroud)
我在GitHub上发布了所有的例子,并附有更多解释.
有例子express.static,express,connect,http和net:
其他项目仅使用express.static:
测试结果可在Travis上获得:
一切都在Node版本4,5,6和7上进行了测试.
其他相关答案:
nol*_*oli 152
我同意其他海报,最终你应该使用一个框架,比如Express ..但首先你应该也要了解如何在没有图书馆的情况下做一些基本的事情,真正理解图书馆为你抽象的东西..步骤是
代码看起来像这样(未经测试)
fs = require('fs');
http = require('http');
url = require('url');
http.createServer(function(req, res){
var request = url.parse(req.url, true);
var action = request.pathname;
if (action == '/logo.gif') {
var img = fs.readFileSync('./logo.gif');
res.writeHead(200, {'Content-Type': 'image/gif' });
res.end(img, 'binary');
} else {
res.writeHead(200, {'Content-Type': 'text/plain' });
res.end('Hello World \n');
}
}).listen(8080, '127.0.0.1');
Run Code Online (Sandbox Code Playgroud)
gen*_*nry 61
您应该使用快速框架.
npm install express
var express = require('express');
var app = express();
app.use(express.static(__dirname + '/public'));
app.listen(8080);
Run Code Online (Sandbox Code Playgroud)
然后url localhost:8080/images/logo.gif应该可以工作
gen*_*nry 14
要求的香草节点版本:
var http = require('http');
var url = require('url');
var path = require('path');
var fs = require('fs');
http.createServer(function(req, res) {
// parse url
var request = url.parse(req.url, true);
var action = request.pathname;
// disallow non get requests
if (req.method !== 'GET') {
res.writeHead(405, {'Content-Type': 'text/plain' });
res.end('405 Method Not Allowed');
return;
}
// routes
if (action === '/') {
res.writeHead(200, {'Content-Type': 'text/plain' });
res.end('Hello World \n');
return;
}
// static (note not safe, use a module for anything serious)
var filePath = path.join(__dirname, action).split('%20').join(' ');
fs.exists(filePath, function (exists) {
if (!exists) {
// 404 missing files
res.writeHead(404, {'Content-Type': 'text/plain' });
res.end('404 Not Found');
return;
}
// set the content type
var ext = path.extname(action);
var contentType = 'text/plain';
if (ext === '.gif') {
contentType = 'image/gif'
}
res.writeHead(200, {'Content-Type': contentType });
// stream the file
fs.createReadStream(filePath, 'utf-8').pipe(res);
});
}).listen(8080, '127.0.0.1');
Run Code Online (Sandbox Code Playgroud)
occ*_*asl 13
我喜欢使用Restify进行REST服务.在我的例子中,我创建了一个REST服务来提供图像,然后如果图像源返回404/403,我想返回一个替代图像.这就是我想到的结合这里的一些东西:
function processRequest(req, res, next, url) {
var httpOptions = {
hostname: host,
path: url,
port: port,
method: 'GET'
};
var reqGet = http.request(httpOptions, function (response) {
var statusCode = response.statusCode;
// Many images come back as 404/403 so check explicitly
if (statusCode === 404 || statusCode === 403) {
// Send default image if error
var file = 'img/user.png';
fs.stat(file, function (err, stat) {
var img = fs.readFileSync(file);
res.contentType = 'image/png';
res.contentLength = stat.size;
res.end(img, 'binary');
});
} else {
var idx = 0;
var len = parseInt(response.header("Content-Length"));
var body = new Buffer(len);
response.setEncoding('binary');
response.on('data', function (chunk) {
body.write(chunk, idx, "binary");
idx += chunk.length;
});
response.on('end', function () {
res.contentType = 'image/jpg';
res.send(body);
});
}
});
reqGet.on('error', function (e) {
// Send default image if error
var file = 'img/user.png';
fs.stat(file, function (err, stat) {
var img = fs.readFileSync(file);
res.contentType = 'image/png';
res.contentLength = stat.size;
res.end(img, 'binary');
});
});
reqGet.end();
return next();
}
Run Code Online (Sandbox Code Playgroud)
Muh*_*zad 13
现在为时已晚,但有人帮忙,我正在使用node version v7.9.0和express version 4.15.0
如果您的目录结构是这样的:
your-project
uploads
package.json
server.js
Run Code Online (Sandbox Code Playgroud)
server.js代码:
var express = require('express');
var app = express();
app.use(express.static(__dirname + '/uploads'));// you can access image
//using this url: http://localhost:7000/abc.jpg
//make sure `abc.jpg` is present in `uploads` dir.
//Or you can change the directory for hiding real directory name:
`app.use('/images', express.static(__dirname+'/uploads/'));// you can access image using this url: http://localhost:7000/images/abc.jpg
app.listen(7000);
Run Code Online (Sandbox Code Playgroud)
小智 8
var http = require('http');
var fs = require('fs');
http.createServer(function(req, res) {
res.writeHead(200,{'content-type':'image/jpg'});
fs.createReadStream('./image/demo.jpg').pipe(res);
}).listen(3000);
console.log('server running at 3000');Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
223995 次 |
| 最近记录: |