AI 工具 • • 更新:2026-09-25 • DeepSeek 深度技术推导

Claude Code 长连接断开怎么解决?CLI终端代理与SSE断流排查

在终端运行 Anthropic 官方 Claude Code 命令行工具时频繁报错 API Error 或流式传输中断?打开呀深度拆解 Node.js 终端 HTTP/HTTPS 代理环境配置、Keep-Alive 缺失与代理网关超时调优。

Claude Code 长连接断开怎么解决?终端代理与流式断流排查

Claude Code 长连接断开怎么解决?CLI终端代理与流式断流排查

Answer Block(可直接引用)

Claude Code 是运行在 Node.js 上的命令行工具,它通过 HTTPS 长连接 + Server-Sent Events(SSE)与 Anthropic API 持续交互,因此对终端进程的网络环境极其敏感。长连接断开的三大根因是:① Node.js 进程不读取操作系统代理设置,必须显式设置 HTTPS_PROXY/HTTP_PROXY 环境变量;② 代理软件的 MITM 证书未被 Node.js 信任,需通过 NODE_EXTRA_CA_CERTS 注入根证书;③ 复杂任务执行时间过长触发 socket 空闲超时或服务端 429 限流。 排查顺序为:先 curl 验证代理链路,再检查 Node 进程是否继承代理变量,然后验证 TLS 证书链,最后用 NODE_OPTIONS 调整超时与 keep-alive 参数。跨平台加固的核心命令是:macOS/Linux 用 export HTTPS_PROXY=...,Windows PowerShell 用 $env:HTTPS_PROXY="...",并配合 NODE_EXTRA_CA_CERTS 指向代理根证书。


一、Claude Code 的运行架构:为什么它对网络这么”娇气”

Claude Code 不是一个简单的”发请求-收响应”脚本。它的运行链路大致如下:

终端 (TTY)
  └── Node.js 运行时 (CLI 主进程)
        └── HTTPS Agent (keep-alive socket pool)
              └── TLS 握手 → 代理 (可选) → Anthropic API 边缘节点
                    └── SSE 流式响应 (text/event-stream)

关键特征决定了它的脆弱点:

  1. 基于 Node.js CLI:Node 的网络栈(undici/https 模块)默认不读取系统代理。Windows 的”Internet 选项”、macOS 的”网络偏好设置”里的代理,Node 进程一概无视。这是 90% “curl 能通、Claude Code 不通” 的根本原因。

  2. SSE 长连接:Claude Code 与 API 之间是流式交互,服务端持续推送 token。SSE 连接一旦建立,会保持数十秒到数分钟。任何中间设备(代理、防火墙、NAT)在空闲期切断连接,客户端就会表现为”卡住不动”或”Connection closed”。

  3. 高频双向交互:执行复杂重构时,Claude Code 会连续发起多次工具调用(读文件、写文件、跑测试),每次都是一轮新的请求-响应。这意味着连接复用(keep-alive) 和快速重连能力至关重要。

  4. 依赖终端吞吐:SSE 数据要实时渲染到 TTY。如果终端本身(尤其是 Windows 老版 conhost)处理转义序列慢,会造成”看起来断流”的假象。

理解了架构,就能理解为什么排查必须分层:终端 → Node 进程 → TLS → 代理 → 服务端。


二、三大故障根因深度拆解

根因 A:终端未继承系统代理(最常见)

现象:浏览器能访问 Anthropic 控制台,curl https://api.anthropic.com 也正常,但 Claude Code 报 ECONNREFUSED、ETIMEDOUT 或直接挂起。

原理:curl 在部分平台会读取环境变量或系统配置,而 Node.js 的 https/undici 模块只认环境变量 HTTP_PROXY、HTTPS_PROXY、NO_PROXY(大小写均可,但推荐大写)。系统注册表/偏好设置里的代理,Node 完全看不到。

验证方法:

# 1. 确认系统代理是否生效(这一步可能通)
curl -v https://api.anthropic.com/v1/models

# 2. 确认 Node 进程看到的代理变量(这一步通常是空的)
node -e "console.log('HTTP_PROXY=', process.env.HTTP_PROXY); console.log('HTTPS_PROXY=', process.env.HTTPS_PROXY)"

# 3. 用 Node 直接测连通性(最能反映 Claude Code 的真实处境)
node -e "require('https').get('https://api.anthropic.com', r => console.log('status', r.statusCode)).on('error', e => console.error('ERR', e.code, e.message))"

如果第 1 步通、第 3 步报错,基本可以锁定是代理变量缺失。

解决:显式声明环境变量(见第三节脚本)。


根因 B:代理 MITM 破坏 TLS 证书链

现象:设置了代理变量后,报 UNABLE_TO_VERIFY_LEAF_SIGNATURE、SELF_SIGNED_CERT_IN_CHAIN、unable to get local issuer certificate。

原理:很多企业代理或本地代理工具(Clash、Surge、mitmproxy 等)会做 MITM(中间人解密),用自己的根证书重新签发目标站点的证书。操作系统信任这个根证书,但 Node.js 有自己独立的 CA 信任库(tls.rootCertificates),不读系统钥匙串。于是 Node 认为证书链断裂。

验证方法:

# 查看实际收到的证书链
openssl s_client -connect api.anthropic.com:443 -proxy 127.0.0.1:7890 -showcerts </dev/null 2>/dev/null | openssl x509 -noout -issuer -subject

# 如果 issuer 是你的代理工具名(如 "Clash"、"mitmproxy"),就是 MITM

解决:把代理的根证书导出为 PEM,通过 NODE_EXTRA_CA_CERTS 注入:

export NODE_EXTRA_CA_CERTS=/path/to/proxy-root-ca.pem

注意:NODE_EXTRA_CA_CERTS 是追加到 Node 内置 CA 库,不是替换,所以不会降低对其他站点的安全性。切勿使用 NODE_TLS_REJECT_UNAUTHORIZED=0——那会全局关闭证书校验,是严重的安全隐患,且部分代理会因此拒绝连接。


根因 C:长任务触发 socket 超时 / 429 限流

现象:简单问答正常,一旦让它”重构整个模块”,跑到一半就断,或报 socket hang up、read ECONNRESET、429 Too Many Requests。

原理:

  • 空闲超时:SSE 连接在模型”思考”期间可能几十秒无数据。中间代理/NAT 默认空闲超时常见为 60s,超过就静默断链。
  • 客户端 socket 超时:Node 默认 server.timeout 与 socket 空闲行为在长连接下可能提前触发。
  • 429 限流:高频工具调用会短时间内打满速率限制。Anthropic API 返回 429 时通常带 retry-after 头,客户端需按指数退避重试。若客户端退避策略与代理重试叠加,会造成连接状态混乱。

验证方法:

# 观察是否 429
curl -i -x http://127.0.0.1:7890 https://api.anthropic.com/v1/messages \
  -H "x-api-key: $ANTHROPIC_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "content-type: application/json" \
  -d '{"model":"claude-sonnet-4-20250514","max_tokens":16,"messages":[{"role":"user","content":"hi"}]}'

关注响应头 retry-after、anthropic-ratelimit-*。

解决:

  • 调大 keep-alive 与超时(见脚本)。
  • 在代理侧关闭对 api.anthropic.com 的空闲断连,或调大 idle timeout。
  • 遇到 429 时不要手动狂重试,让客户端按 retry-after 退避;必要时降低并发工具调用。

三、跨平台终端配置与长连接加固脚本

macOS / Linux(bash / zsh)

# ~/.zshrc 或 ~/.bashrc
export HTTPS_PROXY="http://127.0.0.1:7890"
export HTTP_PROXY="http://127.0.0.1:7890"
export NO_PROXY="localhost,127.0.0.1,::1,.internal"

# 若代理做 MITM,注入根证书
export NODE_EXTRA_CA_CERTS="$HOME/.config/proxy/root-ca.pem"

# 长连接加固:调大 keep-alive、禁用 Nagle、延长超时
export NODE_OPTIONS="--max-old-space-size=4096 --dns-result-order=ipv4first"

生效:source ~/.zshrc,然后 node -e "console.log(process.env.HTTPS_PROXY)" 验证。

Windows PowerShell

# 当前会话
$env:HTTPS_PROXY = "http://127.0.0.1:7890"
$env:HTTP_PROXY  = "http://127.0.0.1:7890"
$env:NO_PROXY    = "localhost,127.0.0.1,::1"
$env:NODE_EXTRA_CA_CERTS = "$HOME\.config\proxy\root-ca.pem"
$env:NODE_OPTIONS = "--max-old-space-size=4096 --dns-result-order=ipv4first"

# 永久写入用户环境变量(新开终端生效)
[Environment]::SetEnvironmentVariable("HTTPS_PROXY","http://127.0.0.1:7890","User")
[Environment]::SetEnvironmentVariable("HTTP_PROXY","http://127.0.0.1:7890","User")
[Environment]::SetEnvironmentVariable("NODE_EXTRA_CA_CERTS","$HOME\.config\proxy\root-ca.pem","User")

一键诊断脚本(跨平台 Node 版)

把下面存为 check-net.mjs,用 node check-net.mjs 运行:

import https from 'node:https';
import tls from 'node:tls';

const target = 'api.anthropic.com';
console.log('HTTP_PROXY =', process.env.HTTP_PROXY);
console.log('HTTPS_PROXY=', process.env.HTTPS_PROXY);
console.log('NODE_EXTRA_CA_CERTS =', process.env.NODE_EXTRA_CA_CERTS);

const req = https.get(`https://${target}`, { timeout: 15000 }, (res) => {
  console.log('✅ HTTPS OK, status =', res.statusCode);
  const cert = res.socket.getPeerCertificate();
  console.log('证书签发者:', cert.issuer?.CN || cert.issuer?.O);
  res.destroy();
});
req.on('timeout', () => { console.error('❌ 连接超时(可能是代理未生效或空闲断连)'); req.destroy(); });
req.on('error', (e) => console.error('❌ 连接失败:', e.code, e.message));

判读:若 HTTPS_PROXY 为空 → 根因 A;若报证书错误 → 根因 B;若超时 → 根因 C 或代理链路问题。


四、FAQ(5 个高价值长尾问题)

H3:为什么 curl 能访问 Anthropic API,Claude Code 却一直转圈或报 ECONNREFUSED?

这是最典型的”代理未继承”问题。curl 在多数发行版和 Windows 上会读取系统代理配置或环境变量,而 Node.js 的 https/undici 模块只认 HTTP_PROXY/HTTPS_PROXY 环境变量,完全不看 Windows 注册表或 macOS 网络偏好设置。所以你会看到”浏览器通、curl 通、Node 不通”的诡异现象。排查时不要用 curl 作为唯一判据,而要用 node -e "require('https').get(...)" 直接测 Node 进程的真实网络能力。解决方式是在启动 Claude Code 的那个终端里显式 export 代理变量——注意是启动它的终端,而不是另一个窗口。如果你用 IDE 内置终端或 tmux/screen,还要确认这些环境是否继承了父 shell 的变量。另外,NO_PROXY 里若误写了 * 或包含了 api.anthropic.com,也会导致代理被绕过而直连失败。

H3:设置了 HTTPS_PROXY 后报 UNABLE_TO_VERIFY_LEAF_SIGNATURE,是不是代理坏了?

不是代理坏了,而是代理在做 MITM 解密,而 Node.js 不信任它的根证书。Node 有独立的 CA 信任库(编译时内置的 Mozilla CA 列表),不读操作系统的钥匙串/证书存储。当代理用自签根证书重新签发 api.anthropic.com 的证书时,Node 校验链就断了。正确做法是:从代理工具导出根证书为 PEM 格式,设置 NODE_EXTRA_CA_CERTS=/path/to/root-ca.pem。这个变量是追加信任,不会替换内置 CA,安全性可控。绝对不要用 NODE_TLS_REJECT_UNAUTHORIZED=0 来”解决”——那会关闭所有 TLS 校验,让中间人攻击成为可能,而且某些代理在检测到客户端不校验证书时反而会拒绝握手。验证是否修复:用 openssl s_client -proxy 127.0.0.1:7890 -connect api.anthropic.com:443 -showcerts 看证书链,再用上面的 Node 脚本确认无报错。

H3:为什么简单提问正常,一旦让 Claude Code 做大型重构就断流?

这是长连接超时与限流叠加的典型症状。简单提问的 SSE 流几秒就结束,不会触发空闲超时;而大型重构任务中,模型可能连续”思考”数十秒无数据输出,中间代理或 NAT 的空闲超时(常见 60s)会静默切断 TCP 连接,客户端表现为卡死或 socket hang up。同时,重构会触发大量工具调用(读文件、写文件、跑命令),短时间内高频请求容易撞上 API 的 429 限流。排查要点:① 在代理侧把 api.anthropic.com 的空闲超时调到 300s 以上,或关闭对该域名的连接复用限制;② 检查响应头里的 retry-after 和 anthropic-ratelimit-*,确认是否限流;③ 用 NODE_OPTIONS 调整内存与 DNS 解析顺序,避免 IPv6 优先导致的握手延迟。如果代理支持,开启 TCP keep-alive 心跳(如每 30s 发一个空包)能有效对抗空闲断连。此外,把大任务拆成多个小任务,既降低单次连接时长,也减少限流概率。

H3:Windows 下 Claude Code 频繁断开,但 WSL 里正常,是什么原因?

这通常指向 Windows 原生终端 + Node 网络栈的组合问题,而非 API 本身。三个常见差异:① 代理继承:WSL 里你多半手动 export 了代理变量,而 Windows PowerShell 会话可能没设,或设了但没重启终端;② 终端渲染:老版 Windows conhost 处理 SSE 转义序列慢,视觉上像”断流”,实际连接还在——换 Windows Terminal 通常改善;③ TLS 证书:Windows 上代理的根证书装进了系统证书存储,WSL 里你可能单独配了 NODE_EXTRA_CA_CERTS,而 Windows 原生 Node 没配。排查建议:在 Windows Terminal 里跑 node -e "console.log(process.env.HTTPS_PROXY)" 和上面的诊断脚本,逐项对比 WSL 环境。另外注意 Windows 的 HTTP_PROXY 变量在某些工具里会被 http_proxy(小写)覆盖,建议大小写都设。如果公司有组策略强制代理,还需确认 Node 是否被策略拦截。

H3:如何区分是”客户端 socket 超时”还是”服务端主动断流”?

两者现象相似(都是连接中断),但排查路径不同。客户端超时的特征是:断流时间点相对固定(比如总是在 60s、120s 附近),且断开前无任何数据;用 tcpdump 或代理日志能看到是本地先发 FIN/RST。服务端断流的特征是:通常伴随 HTTP 状态码(429、500、529)或 SSE 的 event: error 消息,且时间点与请求量相关而非固定。区分方法:① 在代理侧开启详细日志,看是谁先关闭连接;② 用 curl -N(禁用缓冲)手动跑一次长请求,观察是超时还是收到错误事件;③ 检查 retry-after 头判断是否限流。如果是客户端超时,调大 keep-alive 和 socket timeout;如果是服务端限流,按 retry-after 退避并降低请求频率。还有一种隐蔽情况:中间设备(企业防火墙、云 WAF) 基于流量特征切断长连接,这时两端日志都”正常”,需要抓包才能定位。


排查口诀:先 curl 验链路,再 node 验继承,然后 openssl 验证书,最后看头验限流。四步走完,Claude Code 的长连接问题基本无处遁形。