Node.js中ESOCKETTIMEDOUT的复现方法及异常处理问询
如何复现ESOCKETTIMEDOUT并处理该错误避免服务器崩溃
一、复现ESOCKETTIMEDOUT的简单方法
ESOCKETTIMEDOUT是读取超时:连接已成功建立,但客户端在指定时间内未收到服务器发送的后续响应数据。你之前的思路是对的,但需要配合客户端的超时配置才能触发这个错误,具体步骤如下:
1. 搭建挂起响应的测试服务器
用Express写一个接口,发送部分响应后故意挂起,不结束请求:
const express = require('express'); const app = express(); const port = 3000; // 这个接口会发送部分数据后挂起连接 app.get('/hang-response', (req, res) => { // 发送一段部分响应 res.write('This is a partial response...'); // 不调用res.end(),让连接保持打开但不再发送任何数据 }); app.listen(port, () => { console.log(`Test server running on http://localhost:${port}`); });
2. 客户端设置读取超时触发错误
使用request库发送请求时,明确设置readTimeout(读取超时时间),确保这个时间小于服务器挂起的时长:
const request = require('request'); request({ url: 'http://localhost:3000/hang-response', readTimeout: 3000, // 3秒内没收到后续数据就触发读取超时 connectTimeout: 1000 // 连接超时时间(用于区分ETIMEDOUT) }, (err, res, body) => { if (err) { console.error('Error code:', err.code); // 这里会输出ESOCKETTIMEDOUT console.error('Error details:', err); return; } console.log('Full response received:', body); });
运行客户端代码后,3秒内服务器没有发送更多数据,就会触发ESOCKETTIMEDOUT错误。
二、处理ESOCKETTIMEDOUT错误,避免服务器崩溃
要防止这类错误导致服务器崩溃,核心是主动捕获错误,配合全局兜底机制,具体方案如下:
1. 每个请求单独捕获错误
最基础也最关键的是,在每个request调用的回调或Promise中处理错误:
// 回调方式 request({/* 配置 */}, (err, res, body) => { if (err) { if (err.code === 'ESOCKETTIMEDOUT') { // 针对读取超时的特殊处理:比如重试、返回友好提示 console.warn('Request timed out while reading response, retrying...'); // 这里可以加入重试逻辑 } else { // 处理其他错误 console.error('Request failed:', err); } return; } // 正常处理响应 }); // 如果使用request-promise(Promise风格) const rp = require('request-promise'); async function makeRequest() { try { const body = await rp({/* 配置 */}); // 正常处理 } catch (err) { if (err.code === 'ESOCKETTIMEDOUT') { // 处理读取超时 } console.error('Request error:', err); } }
2. 全局兜底捕获未处理异常
作为最后一道防线,捕获全局层面的未处理错误,避免服务器直接崩溃:
// 捕获未处理的Promise拒绝(针对Promise风格的请求) process.on('unhandledRejection', (reason, promise) => { console.error('Unhandled Rejection at:', promise, 'Reason:', reason); // 这里可以做一些清理工作,比如关闭数据库连接 }); // 捕获未捕获的同步/异步异常 process.on('uncaughtException', (err) => { console.error('Uncaught Exception:', err); // 不建议直接忽略,最好优雅退出后重启(比如用PM2自动重启) setTimeout(() => process.exit(1), 1000); });
3. 优化请求与服务器配置
- 合理设置超时参数:根据业务场景调整
readTimeout和connectTimeout,避免过短导致误触发,或过长占用资源。 - 添加重试机制:使用
request-retry等库,对ESOCKETTIMEDOUT这类临时错误进行自动重试。 - 服务器端超时控制:在Express中使用中间件(如
express-timeout-handler),防止请求长时间挂起占用连接资源。
内容的提问来源于stack exchange,提问作者Gautam Kumar Samal
相关产品推荐
相关产品推荐

