NodeJS Express API超时问题求助(EC2与本地环境)
Express高并发大请求超时问题解决
问题场景
本地及EC2上部署的Express后端API,处理少量数据时运行正常,但发送500个单请求大小1MB的并发POST请求时,约2分钟后出现超时,服务器主动关闭Socket。尝试在/calculate接口首行添加res.socket.setTimeout(0);未生效。
错误信息
EC2服务器端错误
BadRequestError: request aborted at IncomingMessage.onAborted (/home/ec2-user/project/node_modules/raw-body/index.js:245:10) at IncomingMessage.emit (node:events:519:28) at IncomingMessage._destroy (node:_http_incoming:224:10) at _destroy (node:internal/streams/destroy:121:10) at IncomingMessage.destroy (node:internal/streams/destroy:83:5) at abortIncoming (node:_http_server:797:9) at socketOnClose (node:_http_server:791:3) at Socket.emit (node:events:531:35) at TCP.<anonymous> (node:net:338:12)
本地客户端错误
node:internal/deps/undici/undici:11730 Error.captureStackTrace(err, this); ^ TypeError: fetch failed at Object.fetch (node:internal/deps/undici/undici:11730:11) at async Promise.all (index 9) at async D:\project\backend.js:49:32 { cause: SocketError: other side closed at Socket.onSocketEnd (node:internal/deps/undici/undici:8280:26) at Socket.emit (node:events:526:35) at endReadableNT (node:internal/streams/readable:1589:12) at process.processTicksAndRejections (node:internal/process/task_queues:82:21) { code: 'UND_ERR_SOCKET', socket: { localAddress: '192.168.100.2', localPort: 62485, remotePort: 3000, remoteFamily: 'IPv4', timeout: undefined, bytesWritten: 2300660, bytesRead: 277 } } }
依赖与环境
- Node版本:v20.14.0
- 依赖版本:
"dependencies": { "body-parser": "^1.20.2", "cors": "^2.8.5", "express": "^4.19.2" }
解决方法
1. 修改Express服务器全局超时设置
Express 4.x中,app.listen()返回的是Node原生http.Server实例,直接设置该实例的超时属性即可覆盖默认的2分钟超时规则。
修改后的API代码:
const express = require('express'); const cors = require('cors'); const bodyParser = require('body-parser'); const app = express(); app.use(cors()); app.use(bodyParser.json({limit: '30mb'})) app.use(bodyParser.urlencoded({ limit: '30mb', extended: true })); app.post('/calculate', async (req, res) => { // 原有业务代码 }); // 获取server实例并设置超时(0表示禁用超时,也可设置具体毫秒值如1800000表示30分钟) const server = app.listen(3000, () => { console.log(`App listening on port 3000`); }); server.setTimeout(0);
2. 为什么res.socket.setTimeout(0)无效?
请求在到达路由处理函数之前,可能已经在body-parser解析请求体的阶段触发了超时。全局设置服务器超时会覆盖所有请求的超时规则,包括请求体解析阶段,因此更有效。
3. 额外优化建议
- 控制并发数:一次性发送500个并发请求可能超出服务器默认连接上限,可将请求拆分成小批次发送(比如每次50个),避免连接耗尽。
- 调整连接参数:服务器侧可设置
server.maxConnections提升最大连接数;客户端侧调整Node全局Agent的最大socket数:// 客户端代码中添加 const http = require('http'); http.globalAgent.maxSockets = 100; - 客户端超时控制:在
fetch请求中添加主动超时逻辑,避免客户端无限制等待:const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), 300000); // 设置5分钟超时 batchRequests.push(fetch('ip/calculate', { method: 'POST', body: JSON.stringify({file}), headers: { 'Content-Type': 'application/json' }, signal: controller.signal }).finally(() => clearTimeout(timeoutId)));
内容的提问来源于stack exchange,提问作者klopton2662
相关产品推荐
相关产品推荐

