背景說明 最近在工作項目中有下麵一個場景: 使用Node.js的express框架實現了一個文件系統伺服器端,其中有個API用於客戶端上傳文件。客戶端使用Node.js的HttpClient來調用伺服器端的API上傳文件。 客戶端在上傳小文件時沒有任何問題,在上傳大文件時httpClient請求報錯 ...
背景說明
最近在工作項目中有下麵一個場景:
使用Node.js的express框架實現了一個文件系統伺服器端,其中有個API用於客戶端上傳文件。客戶端使用Node.js的HttpClient來調用伺服器端的API上傳文件。
客戶端在上傳小文件時沒有任何問題,在上傳大文件時httpClient請求報錯了下麵的錯誤,
{ [Error: socket hang up] code: 'ECONNRESET' }
google了很多資料,最後看了一下Node.js的相關源碼終於知道了該問題的原因和解決辦法。
問題原因
出現該問題的原因是:Node.js提供的HttpServer預設設置了超時時間為2分鐘,當一個請求的處理時間超過2分鐘,HttpServer會自動將該請求的socket關閉掉,於是客戶端便收到了 ECONNRESET 的錯誤信息了。可以參考Node.js的源碼。
下麵我們使用了一個例子來驗證一下。
伺服器端:
伺服器端使用express框架,註冊了一個路徑為““ 的 GET 方法路由處理函數。在該路由處理函數中,通過setTimeout方式設置了超時處理,3分鐘後超時才會對請求進行相應。
const express = require('express'); const util = require('util'); const app = express(); app.get("/", function(req, res, next) { util.log("Received a request."); setTimeout(function() { res.setHeader('transfer-encoding', 'chunked'); res.status(200); util.log("timeout") res.write("hello world"); res.end(); }, 3 * 60 * 1000) }); var server = app.listen(3001, function() { sutil.log("server listening at port 3001......"); });
客戶端:
客戶端通過調用http.request方法請求伺服器端的介面,並列印返回的信息。
const http = require('http'); const util = require('util') var opt = { host: 'localhost', port: 3001, method: 'GET', }; var req = http.request(opt, function(res) { util.log('STATUS:', res.statusCode); res.setEncoding('utf8'); var resultText = ''; res.on('data', (chunk) => { resultText += chunk; }); res.on('end', () => { util.log(resultText); }); }); req.on('error', (e) => { util.log(e); }); util.log("start request...") req.end();
先啟動伺服器端,然後啟動客戶端。請求的結果如下所示:
伺服器端:
bbash-3.2$ node app.js 12 Nov 21:02:16 - server listening at port 3001...... 12 Nov 21:02:22 - Received a request. 12 Nov 21:05:22 - timeout
客戶端:
bash-3.2$ node app.js 12 Nov 21:02:22 - start request... 12 Nov 21:04:22 - { [Error: socket hang up] code: 'ECONNRESET' }
通過上面的運行結果可以看到,客戶端在請求等待了2分鐘之後,就報錯了 ECONNRESET 的錯誤。
解決措施
解決措施:調用伺服器端的server.setTimeout()方法將伺服器端的超時設置得大一點或者直接將超時機制關閉(將超時時間設置為0即可關閉)。
就使用上面的代碼,客戶端不變,伺服器在文件最後調用server.setTimeout()方法,如下所示,
var server = app.listen(3001, function() { sutil.log("server listening at port 3001......"); }); server.setTimeout(0)
先啟動伺服器端,然後再啟動客戶端,運行結果如下:
伺服器端:
bash-3.2$ node app.js 12 Nov 21:37:22 - server listening at port 3001...... 12 Nov 21:37:29 - Received a request. 12 Nov 21:40:29 - timeout
客戶端:
bash-3.2$ node app.js 12 Nov 21:37:29 - start request... 12 Nov 21:40:29 - STATUS: 200 12 Nov 21:40:29 - hello world
從上面運行結果可見,客戶端能夠正常接收到伺服器端的返回結果了。
(done)