Node.js调用PHP接口频繁断连的根本原因是中间设备主动回收空闲HTTP连接,需通过http.Agent配置keepAliveTimeout≥后端超时、PHP禁用输出缓冲、Nginx启用HTTP/1.1并清除Connection头来协同解决。

Node.js 调用 PHP 接口频繁断连的根本原因
不是 Node.js 或 PHP 单方面的问题,而是 HTTP 连接在空闲时被中间设备(如 Nginx、负载均衡器、云服务商 SLB、甚至运营商网关)主动回收。默认情况下,keep-alive 连接超时往往只有 60–75 秒,而 Node.js 的 http.Agent 默认 keepAliveTimeout 是 5000ms,远低于后端实际保活窗口,导致复用连接时突然收到 ECONNRESET 或 socket hang up。
用 http.Agent 配置长连接 + 心跳参数
必须显式创建并复用 http.Agent 实例,不能依赖默认 agent;关键参数要对齐后端(尤其是 Nginx 的 keepalive_timeout):
-
keepAlive: true— 启用复用 -
keepAliveMsecs: 30000— 每 30 秒发一次 TCP keepalive probe(OS 层,需系统支持) -
maxSockets: 50— 避免连接数爆炸,按压测结果调整 -
timeout: 10000— 请求级超时,和心跳无关,但影响失败感知速度 -
keepAliveTimeout: 65000— 必须 ≥ 后端 keepalive_timeout(比如 Nginx 设了 65s,这里至少设 65000)
示例:
const http = require('http');
const agent = new http.Agent({
keepAlive: true,
keepAliveMsecs: 30000,
maxSockets: 50,
timeout: 10000,
keepAliveTimeout: 65000
});
// 所有请求必须传入 agent
http.get('http://php-api.example.com/status', { agent }, (res) => {
// ...
});
PHP 端必须关闭输出缓冲 & 显式 flush
Node.js 发起的 keep-alive 请求,如果 PHP 响应未及时写出或被缓冲,连接会卡住,最终被中间层断开。常见陷阱:
立即学习“PHP免费学习笔记(深入)”;
- PHP 开启了
output_buffering(默认可能为 4096 或 On)→ 导致响应延迟发出 - 使用了
ob_start()但没ob_end_flush() - 没调用
flush()或ob_flush()强制推送响应头+body
建议在 PHP 入口加:
@ini_set('output_buffering', 'off');
@ini_set('zlib.output_compression', false);
if (function_exists('apache_setenv')) {
@apache_setenv('no-gzip', '1');
}
header('Connection: keep-alive');
ob_implicit_flush(true);
心跳检测不等于 HTTP 轮询,别在业务层硬加 /health
很多团队误以为“每 30 秒 GET /health 就是心跳”,这反而加重服务负担,且无法防止真实业务连接被断。真正有效的保活是:
- TCP 层:靠
keepAliveMsecs+ OS 内核参数(如/proc/sys/net/ipv4/tcp_keepalive_time)维持链路 - HTTP 层:靠
keepAliveTimeout对齐后端,让连接在空闲期不被服务端主动 close - 应用层心跳(如 /health)只应在连接池空闲时由 agent 主动探测,而非业务定时器无差别调用
注意:http.Agent 不提供内置心跳接口,若真需应用层探测,建议封装一个带重试的轻量 HEAD / 请求,在连接复用前触发,而非固定间隔轮询。
最易忽略的一点:Nginx 的 proxy_http_version 1.1 和 proxy_set_header Connection '' 必须配置,否则 upstream 会收不到 keep-alive 指令,所有努力都白搭。











