簡體   English   中英

Node.js服務器停止響應

[英]Node.js server stops responding

我正在處理node.js HTTPS請求。 我已經進行了足夠的研究,還檢查了所有內容,但我仍然認為我缺少某些內容。 我要實現的是,當有人向我的URL發送HTTPS GET請求時,我必須向他們發送一個文件作為響應,以便他們可以下載。 一切正常,我已經實現了“ FS”,“ HTTPS”,並且也以適當的方式編寫,但是當我平均每40個請求中的每1000個請求失敗后,在我的URL上發送大量流量時。

我不確定為什么會這樣,我也設置了這個:

var https = require('https');
https.globalAgent.maxSockets = Infinity;

誰能幫我理解和解決問題? 提前致謝!

安韋什

編輯 :根據要求,我正在添加我的代碼,由於隱私原因,我刪除了幾行代碼。

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();
                // });          

});

一般問題

我不知道您的服務器在什么操作系統上運行。 如果是Linux或Windows,請查看有關如何增加並發連接數量的答案:

您的問題可能出在您的客戶端(在注釋中寫的那樣在Windows上運行)或服務器(您未指定其OS)上。 同樣,問題可能出在您的程序或操作系統上,甚至是客戶端和服務器之間的其他一些問題,例如代理等。

您可以使用Apache ab命令來測試您的服務器,以便至少可以消除發送請求的程序在此處出錯的可能性。 例如:

ab -n 10000 -c 1000 -k http://localhost:8080/

這將總共發送10000個請求,一次發送1000個。

請參見關於如何測試與服務器的詳細信息ab

封鎖作業

這是您的問題:

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示例 它或多或少地完成了您在此所做的工作。 在此進行更詳細的說明。

路徑遍歷

我會提出的另一個建議是保護您的服務器免受路徑遍歷攻擊。 因此,當您使用以下命令設置文件名時:

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');
            });

        });

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM