You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解决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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 00:37:24