Node.js 超时配置完全指南

无限超时是生产事故的隐形炸弹。本文系统讲解入站请求超时、出站调用超时、Promise 超时包装、超时值的选择方法与超时错误处理。

最佳实践
事件循环与异步任务流转插画

Node.js 的 http.Server 默认无超时,多数 HTTP 客户端默认无限等待——生产环境必须显式配置:服务端设 requestTimeout/headersTimeout 防慢速攻击,客户端用 AbortSignal.timeout() 控制出站调用,下游超时略小于上游超时逐层收敛。

为什么超时是可靠性基石

下游服务无响应时,没有超时的调用会永远挂起——连接、内存、事件循环资源被持续占用,直至整个服务被拖垮。慢速攻击(Slowloris)正是利用"无限等待":缓慢发送请求头耗光连接池。超时的本质是资源保护。

入站请求:服务端超时

const server = http.createServer(app);

server.requestTimeout = 300_000;   // 完整请求 5 分钟上限(Node 18+)
server.headersTimeout = 60_000;    // 接收请求头 60 秒(防 Slowloris)
server.keepAliveTimeout = 5_000;   // keep-alive 空闲 5 秒

headersTimeout 必须大于 keepAliveTimeout(Node 官方要求),且注意前置 Nginx/负载均衡的超时要与之协调——代理 60 秒、应用 300 秒的组合会让代理先断。

出站调用:客户端超时

// fetch:AbortSignal.timeout 是现代标准写法
const response = await fetch('https://api.example.com/data', {
  signal: AbortSignal.timeout(5000),   // 5 秒超时
});

// 需要更精细控制(连接 vs 总时长)
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), 5000);
try {
  await fetch(url, { signal: controller.signal });
} finally {
  clearTimeout(timer);
}

axios:{ timeout: 5000 };数据库客户端、Redis 客户端同理——每个网络出口都要有超时。

Promise 通用超时包装

function withTimeout(promise, ms, label = '操作') {
  return Promise.race([
    promise,
    new Promise((_, reject) =>
      setTimeout(() => reject(new Error(`${label}超时(${ms}ms)`)), ms)
    ),
  ]);
}

await withTimeout(heavyComputation(), 3000, '数据处理');

注意:Promise.race 只停止"等待",被包装的操作本身还在跑——资源真正释放要靠 AbortController 传导取消信号。

超时值怎么定

  1. 从数据出发:看下游 P99 延迟,超时设为 P99 的 2-3 倍;
  2. 逐层收敛:网关 30s → 服务 25s → 下游调用 20s——上游必须比下游先超时,否则重试雪崩;
  3. 区分操作类型:读操作严格(秒级),写/批处理宽松(分钟级);
  4. 留出重试预算:总超时 = 单次超时 × 重试次数 + 退避时间。

超时错误的处理

try {
  await fetch(url, { signal: AbortSignal.timeout(5000) });
} catch (err) {
  if (err.name === 'TimeoutError' || err.name === 'AbortError') {
    // 超时的正确响应:快速失败 + 降级 + 重试(带熔断)
    return cachedFallback();
  }
  throw err;
}

超时错误应该单独统计——超时率上升是下游劣化的最早信号,比错误率更敏感。

确认超时发生在哪个下游

连接建立、等待响应头和读取响应体的超时应记录为不同错误类型。Node.js 应用接入观测云 APM 后,已支持的客户端调用可以提供耗时和错误信息;未被自动覆盖的调用应手动建 Span。把超时预算、重试次数和取消原因写入脱敏日志,再与链路对照,避免把调用方主动取消误判成下游故障。

接入文档:Node.js APM 接入 · 日志采集 · 监控器与告警策略。

常见问题(FAQ)

Q:keep-alive 超时和 LB 空闲超时怎么协调?

应用的 keepAliveTimeout 应大于前置负载均衡的空闲超时——否则应用先关连接,LB 复用已断连接报 502。经典组合:ALB 60s,Node keepAlive 65s。

Q:超时后重试有什么讲究?

指数退避 + 抖动(jitter)防惊群;只重试幂等操作与明确的网络错误;下游已过载时熔断器(circuit breaker)停止重试——重试风暴会把"慢"打成"死"。

Q:setTimeout 计时器本身可靠吗?

事件循环被阻塞时计时器延迟触发——超时精度依赖事件循环健康。事件循环延迟本身也应纳入监控。


参考文档

本文依据公开文档整理,示例需按项目依赖版本验证;不将文档中的性能描述视为本项目实测结果。

延伸阅读

获取专属方案

联系我们

加入社区

微信扫码
加入官方交流群

立即体验

在线开通,按量计费,真正的云服务!

立即开始

选择观测云版本

代码托管平台