如何解决Express.js与Node.js中服务器超时重复执行回调的问题
解决Node.js请求超时后API回调重复执行的问题
问题分析
当服务器设置的超时时间短于API处理耗时,服务器会在超时后终止连接,但如果未正确处理超时事件,会引发两个核心问题:
- 浏览器因收到空响应自动重试请求,触发回调再次执行
- 未完成的异步操作仍在后台运行,后续尝试发送响应会引发错误
解决方案
通过以下步骤处理超时,阻止重复执行并返回合理响应:
1. 监听单个请求的超时事件
在API回调中监听请求对象的timeout事件,一旦触发就立即返回超时响应,同时终止请求连接。
2. 标记请求处理状态
用变量记录请求是否已完成处理,避免超时后异步操作完成时重复发送响应。
3. 终止超时后的异步操作
在异步任务中监听超时事件,取消未完成的操作,避免不必要的资源消耗。
修改后的代码示例
app.get('/', async (req, res) => { let isHandled = false; // 监听请求超时事件 req.on('timeout', () => { if (isHandled) return; isHandled = true; // 返回408请求超时状态码及提示 res.status(408).send('请求超时,请稍后重试'); // 终止请求连接,阻止后续处理 req.destroy(); }); try { console.log("API function called"); // 模拟耗时操作,同时监听超时以取消任务 await new Promise((resolve, reject) => { const timer = setTimeout(resolve, 10000); req.on('timeout', () => { clearTimeout(timer); reject(new Error('请求超时')); }); }); if (isHandled) return; isHandled = true; res.send('success'); } catch (err) { if (isHandled) return; isHandled = true; res.status(500).send(`错误:${err.message}`); } }); const PORT = 5000; const server = app.listen(PORT, () => { console.log(`Server is running on port ${PORT}.`); }); server.timeout = 7000;
代码说明
isHandled变量:确保响应仅发送一次,避免重复处理req.on('timeout'):触发超时后立即返回明确的408响应,终止请求连接- 异步任务内的超时监听:取消定时器并拒绝Promise,终止后台耗时操作
修改后,超时发生时会直接返回合理响应,浏览器不会因空响应触发重试,控制台只会输出一次“API function called”。
内容的提问来源于stack exchange,提问作者Sourav Garg
相关产品推荐
相关产品推荐

