问题背景
自从 Node.js 8.0 开始,http server 增加了一个默认配置 keepAliveTimeout = 5000
,它会自动销毁超过 5 秒的空闲连接。
或者在源码里最后一行也可以找到 node/_http_agent.js at main · nodejs/node
通过 node-modules/agentkeepalive#58 的示例代码,非常容易重现出服务端 Keep Alive 超时的效果,就是客户端复用「Keep Alive」 的 socket connection 会立刻触发 ECONNRESET
异常,因为此 socket 已经被服务端认为空闲超时强制断开了。
err stringify: {
"message":"connect ETIMEDOUT 39.96.33.114:443","name":"Error",
"stack":"Error: connect ETIMEDOUT 39.96.33.114:443\n at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1148:16)",
"config": {
"url":"xxxx",
"method":"post",
"data":"token=dJC1X1O9z7TsmARBoJxSSUY1TlWxKigRHw~~&templateId=ce0adbff97a2b6361nY~&needData=1",
"headers":{
"Accept":"application/json, text/plain, */*",
"Content-Type":"application/x-www-form-urlencoded",
"User-Agent":"axios/0.21.4",
"Content-Length":325
},
"transformRequest":[null],
"transformResponse":[null],
"timeout":0,
"xsrfCookieName":"XSRF-TOKEN",
"xsrfHeaderName":"X-XSRF-TOKEN",
"maxContentLength":-1,
"maxBodyLength":-1,
"transitional":{
"silentJSONParsing":true,
"forcedJSONParsing":true,
"clarifyTimeoutError":false}
},
"code":"ETIMEDOUT"
};
err name: Error err message: connect ETIMEDOUT 39.96.33.114:443
err stack: Error: connect ETIMEDOUT 39.96.33.114:443 at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1148:16)
ECONNRESET VS ETIMEDOUT
这里注意区分下 ECONNRESET 与 ETIMEDOUT 的区别
ECONNRESET 为读取超时,当服务器太慢无法正常响应时就会发生 {"code":"ECONNRESET"} 错误,例如上面介绍的 socket hang up 例子。
ETIMEDOUT 为链接超时,是指的在客户端与远程服务器建立链接发生的超时,
解决 ECONNRESET 错误的话
, 配置 **设置 http server socket 超时时间**
解决 ETIMEDOUT
, 配置 Agent 里的timeout 参数
一种解决方式:
const axios = require('axios');
const http = require('http');
const https = require('https');
module.exports = axios.create({
//60 sec timeout
timeout: 60000,
//keepAlive pools and reuses TCP connections, so it's faster
httpAgent: new http.Agent({ keepAlive: true }),
httpsAgent: new https.Agent({ keepAlive: true }),
//follow up to 10 HTTP 3xx redirects
maxRedirects: 10,
//cap the maximum content length we'll accept to 50MBs, just in case
maxContentLength: 50 * 1000 * 1000
});
另外解决方式:
// 安装 agentkeepalive 包
npm install agentkeepalive --save
// 配置: axios.js
module.exports = axios.create({
// 60 sec timeout
timeout: 1 * 60 * 1000,
// keepAlive pools and reuses TCP connections, so it's faster
httpAgent: new Agent({
maxSockets: 100,
maxFreeSockets: 10,
timeout: 1 * 60 * 1000,
freeSocketTimeout: 1 * 60 * 1000,
keepAlive: true
}),
httpsAgent: new Agent.HttpsAgent({
maxSockets: 100,
maxFreeSockets: 10,
timeout: 2 * 60 * 1000,
freeSocketTimeout: 1 * 60 * 1000,
keepAlive: true
}),
// follow up to 10 HTTP 3xx redirects
maxRedirects: 10,
// cap the maximum content length we'll accept to 50MBs, just in case
maxContentLength: 50 * 1000 * 1000
});
最后采用 agentkeepalive, 理由:
What's different from original http.Agent
?
keepAlive=true
by default- Disable Nagle's algorithm:
socket.setNoDelay(true)
- Add free socket timeout: avoid long time inactivity socket leak in the free-sockets queue.
- Add active socket timeout: avoid long time inactivity socket leak in the active-sockets queue.
- TTL for active socket.
参考文章: