如何使用Node.js HTTP模块处理跨服务API调用错误?
问题分析与解决方案
一、为什么getId接口抛错时,addUser仍会进入data事件回调?
你在Server2里直接throw new Error,但Express框架遇到未捕获的同步错误时,会默认返回500状态码的HTML错误页面,不会直接断开请求连接。这意味着Server1的HTTP请求并没有触发error事件(该事件仅在网络级错误,比如连接失败、DNS解析失败时触发),而是正常接收到了Server2返回的HTML响应数据——所以res.on('data')会被触发,尝试把HTML内容解析成JSON,自然就会抛出语法错误。
二、正确的错误处理方式
1. 先修复Server2的错误返回格式
让Server2在出错时返回JSON格式的错误信息,而非默认的HTML,这样Server1能正确识别错误:
// Server2 修改后的代码 app.get('/api/getId', (req, res) => { // 主动返回JSON错误,替代直接throw res.status(500).json({ error: 'getId api error' }); }); // 或者用Express全局错误中间件捕获所有未处理的错误 app.use((err, req, res, next) => { res.status(500).json({ error: err.message }); });
2. Server1端的完整错误处理优化
针对HTTP请求和数据解析环节,需要做好以下几点:
- 处理流式数据拼接:
data事件可能多次触发(数据分块传输),必须拼接所有数据后再解析 - 检查响应状态码:先判断响应状态码是否在成功范围(2xx),非成功状态直接处理错误
- 捕获JSON解析异常:用
try-catch包裹JSON.parse,避免解析失败导致进程崩溃 - 完善错误监听:同时监听请求的
error事件和响应的error事件 - 设置请求超时:避免请求长时间挂起
修改后的Server1代码:
// Server1 修改后的代码 app.get('/api/addUser/:userName', (req, res) => { const options = { host: 'localhost', port: 3090, path: '/api/getId', method: 'GET', headers: { accept: 'application/json' }, timeout: 5000 // 设置5秒超时 }; const reqToServer2 = http.request(options, (server2Res) => { // 先判断响应状态码 if (server2Res.statusCode < 200 || server2Res.statusCode >= 300) { errorCounter.add(1); return res.status(500).json({ error: `Server2返回错误状态码:${server2Res.statusCode}` }); } let rawData = ''; // 拼接分块数据 server2Res.on('data', (chunk) => { rawData += chunk; }); // 数据接收完成后处理 server2Res.on('end', () => { try { const userId = JSON.parse(rawData); const user = { userName: req.params.userName, userId }; users.push(user); res.json(user); // 给客户端返回成功响应 } catch (parseErr) { errorCounter.add(1); res.status(400).json({ error: '解析Server2响应失败', details: parseErr.message }); } }); }); // 监听请求错误(如连接失败、超时) reqToServer2.on('error', (err) => { errorCounter.add(1); res.status(500).json({ error: '请求Server2失败', details: err.message }); }); // 监听超时 reqToServer2.on('timeout', () => { reqToServer2.destroy(); errorCounter.add(1); res.status(504).json({ error: '请求Server2超时' }); }); reqToServer2.end(); });
关键优化点说明
- 外层
try-catch无法捕获http.request回调里的异步错误,所以移除了无效的外层捕获逻辑 - 把数据解析逻辑移到
end事件,确保处理的是完整的响应数据 - 针对不同错误场景(网络错误、状态码错误、解析错误、超时)分别处理,更新错误计数器并返回明确的错误信息
内容的提问来源于stack exchange,提问作者bunny
相关产品推荐
相关产品推荐

