我正在处理node.js HTTPS请求。我做了足够的研究并检查了所有的事情,但我仍然觉得我错过了一些东西。 我想要实现的是,当有人向我的URL发送HTTPS GET请求时,我必须向他们发送一个文件作为响应,以便他们可以下载。一切正常,我已经实现了“FS”,“HTTPS”,并且它也以适当的方式写入,但是当我在每1000个请求之后在我的URL上发送大量流量时,平均有40个请求失败。
我不确定为什么会这样,我也设置了这个:
var https = require('https');
https.globalAgent.maxSockets = Infinity;
有谁可以帮我理解和解决问题? 提前谢谢!
Anvesh
编辑:根据要求我正在添加我的代码,因为隐私,我删除了几行代码。
var https = require('https');
https.globalAgent.maxSockets = Infinity;
//var port = process.env.port || 1337;
fileSystem = require('fs'),
fileToWriteLog = require('fs'),
path = require('path');
var mime = require('mime');
var cors = require('cors');
var XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest;
var express = require('express'),
app = module.exports.app = express();
app.use(cors());
// Created to use HTTPS
var options = {
pfx: fileSystem.readFileSync('Certificate/key.pfx'),
passphrase: 'XXX'
};
var server = https.createServer(options,app);
var io = require('socket.io').listen(server); //pass a https.Server instance
var port = 8080;
console.log(process.env.PORT);
server.listen(port,"0.0.0.0", function () {
console.log("Secure Express server listening on port " + port);
}); //listen on port 8082
// routing
app.get('/stream/:patam1/:param2', function (request, response) {
var patam1 = request.param("patam1");
var param2 = decodeURIComponent(request.param("param2"));
var filePath = "XXXX" + param2;
console.log(filePath);
var stat = fileSystem.statSync(filePath);
response.writeHead(200, {
'Content-Type': 'XXX',
'Content-Length': stat.size
});
var readStream = fileSystem.createReadStream(filePath);
readStream.on('data', function (data) {
var flushed = response.write(data);
// Pause the read stream when the write stream gets saturated
if (!flushed)
readStream.pause();
});
response.on('drain', function () {
// Resume the read stream when the write stream gets hungry
readStream.resume();
});
// readStream.on('end', function () {
// response.end();
// });
});
答案 0 :(得分:0)
我不知道您的服务器运行的是什么操作系统。如果它是Linux或Windows,那么请看看你可以采取哪些措施来增加可能的并发连接数:
您在这里遇到的问题可能是您的客户端(在评论中写的在Windows上运行)或服务器(您没有指定其操作系统)。问题也可能出在您的程序或操作系统上,甚至是客户端和服务器之间的其他问题,如代理等。
您可以使用Apache ab
命令来测试服务器,这样至少可以消除发送请求的程序在此处出错的可能性。 E.g:
ab -n 10000 -c 1000 -k http://localhost:8080/
这将总共发送10000个请求,一次发送1000个。
有关如何使用ab
测试服务器的详细信息,请参阅this。
这是你的问题:
var stat = fileSystem.statSync(filePath);
在处理程序中使用阻止(同步)调用时,始终会遇到并发连接问题。
我不知道这是否是唯一的问题,但只有当您希望服务器能够很好地处理并发连接时,才需要使用异步调用。使用stat
代替statSync
。
同步功能适用于程序启动时的一次性作业,例如使用readFileSync
填充options
,而不是在事件处理程序中运行。
有关如何从磁盘提供文件而无需任何同步调用的信息(使用Express,不使用Express等),请参阅此答案。参见:
您根本不需要使用stat
(或statSync
)。您不必设置Content-length标头,因为Node可以使用分块编码,您可以只传输数据。
我会改变这个:
app.get('/stream/:patam1/:param2', function (request, response) {
var patam1 = request.param("patam1");
var param2 = decodeURIComponent(request.param("param2"));
var filePath = "XXXX" + param2;
console.log(filePath);
var stat = fileSystem.statSync(filePath);
response.writeHead(200, {
'Content-Type': 'XXX',
'Content-Length': stat.size
});
var readStream = fileSystem.createReadStream(filePath);
readStream.on('data', function (data) {
var flushed = response.write(data);
// Pause the read stream when the write stream gets saturated
if (!flushed)
readStream.pause();
});
response.on('drain', function () {
// Resume the read stream when the write stream gets hungry
readStream.resume();
});
// readStream.on('end', function () {
// response.end();
// });
});
对于这样的事情:
app.get('/stream/:patam1/:param2', function (request, response) {
var patam1 = request.param("patam1");
var param2 = decodeURIComponent(request.param("param2"));
var filePath = "XXXX" + param2;
console.log(filePath);
response.set('Content-Type', 'XXX');
var readStream = fileSystem.createReadStream(filePath);
readStream.on('open', function () {
response.set('Content-Type', 'XXX');
readStream.pipe(response);
});
readStream.on('error', function () {
response.set('Content-Type', 'text/plain');
response.status(404).end('Not found');
});
});
在GitHub上查看我的node-static-http-servers项目,特别是express example。它或多或少地影响了你在这里所做的事情。它更详细地解释了here。
我的另一个建议是保护您的服务器免受路径遍历攻击。因此,当您使用以下命令设置文件名时
var filePath = "XXXX" + param2;
最好使用path
模块:
var filePath = path.join("XXXX", param2);
然后测试它是否不在您要提供的目录之外,例如:
if (filePath.indexOf('XXXX/') !== 0) {
return response.status(403).end('Forbidden');
}
/
中的indexOf
斜线非常重要。
而不是:
var filePath = "XXXX" + param2;
console.log(filePath);
var stat = fileSystem.statSync(filePath);
response.writeHead(200, {
'Content-Type': 'XXX',
'Content-Length': stat.size
});
var readStream = fileSystem.createReadStream(filePath);
readStream.on('data', function (data) {
var flushed = response.write(data);
// Pause the read stream when the write stream gets saturated
if (!flushed)
readStream.pause();
});
response.on('drain', function () {
// Resume the read stream when the write stream gets hungry
readStream.resume();
});
你可以这样写:
// check for path traversal as I described above:
var filePath = path.join("XXXX", param2);
if (filePath.indexOf('XXXX/') !== 0) {
return response.status(403).end('Forbidden');
}
console.log(filePath);
fileSystem.stat(filePath, function (err, stat) {
if (err) {
response.set('Content-Type', 'text/plain');
return response.status(404).end('Not found');
}
var readStream = fileSystem.createReadStream(filePath);
readStream.on('open', function () {
response.set('Content-Type', 'XXX');
response.set(Content-Length': stat.size);
readStream.pipe(response);
});
readStream.on('error', function () {
response.set('Content-Type', 'text/plain');
response.status(404).end('Not found');
});
});