Administrator
发布于 2026-07-16 / 3 阅读
0
0

Codex 断网后总要重连 5 次?macOS 代理下的 WebSocket 修复指南

适用场景:Codex Desktop 一直开着,网络中断后已经恢复,浏览器也能正常上网,但 Codex 下一次发送消息时仍会依次重试 1/5 到 5/5,等待很久后才恢复。

这类问题看起来像“Codex 服务器不稳定”,但如果浏览器已经恢复、只有 Codex 固定重试五次,优先排查的通常不是普通断网,而是 代理切换后遗留的 WebSocket 路由或会话恢复问题

本文整理一套在 macOS 上可回滚、风险较低的排查方法。核心原则只有三个:

  • 先用日志确认是不是 WebSocket 五次重试;
  • 先确认代理真实监听端口,绝对不要照抄别人的端口;
  • 不修改 ~/.codex/config.toml,只为 Codex 显式设置代理环境变量。

一、典型症状

高置信度的故障模式通常同时满足以下条件:

  1. Codex Desktop 在网络中断前后始终保持打开;
  2. 网络恢复后,浏览器和网页版 ChatGPT 可以正常访问;
  3. Codex 第一次发送新请求时固定经历五次重试;
  4. 日志出现 responses_websocketConnection reset by peerfalling back to HTTP

典型日志形态类似:

target=codex_api::endpoint::responses_websocket
failed to connect to websocket: Connection reset by peer
retrying ... 1/5 ... 5/5
falling back to HTTP

这更像是代理后的 WebSocket 连接在网络变化后变“陈旧”了,并不等于登录失效,也不代表历史任务损坏。

二、先查日志,不要先清缓存

在终端执行:

rg -i "network_changed|responses_websocket|retry|falling back|connection reset" \
  "$HOME/Library/Logs/com.openai.codex" "$HOME/.codex" 2>/dev/null

如果没有安装 rg,可以改用系统自带的 grep

grep -RinE "network_changed|responses_websocket|retry|falling back|connection reset" \
  "$HOME/Library/Logs/com.openai.codex" "$HOME/.codex" 2>/dev/null

日志位置和格式可能随 Codex 版本变化。这里只做只读搜索,不要编辑 SQLite 日志库或状态文件。

三、确认代理的真实监听端口

先查看 macOS 当前系统代理:

scutil --proxy

再查看本机正在监听的 TCP 端口:

lsof -nP -iTCP -sTCP:LISTEN

找到代理客户端对应的 HTTP 或 Mixed 端口后,再单独确认:

lsof -nP -iTCP:<实际端口> -sTCP:LISTEN

例如某台机器可能使用 7892,但不同客户端、不同设备的端口并不一样。如果把一个没有监听的端口写进 Codex 配置,原本偶发的重连会直接变成完全无法连接。

还可以用一次代理请求验证链路:

curl -x http://127.0.0.1:<实际端口> -I https://chatgpt.com

这里主要看请求能否稳定完成。即使返回 403,也可能说明代理到目标站点的网络链路是通的;不要只用业务状态码判断代理进程是否存活。

四、推荐修复:给 Codex 显式设置代理

我把安全修改流程做成了一个可复用技能:

安装或下载技能后,进入技能目录,先查看当前状态:

python3 scripts/configure_proxy_env.py status

确认端口确实在监听后,再执行:

python3 scripts/configure_proxy_env.py apply \
  --proxy-url http://127.0.0.1:<实际端口>

脚本只管理 ~/.codex/.env 中的三个变量:

HTTP_PROXY=http://127.0.0.1:<实际端口>
HTTPS_PROXY=http://127.0.0.1:<实际端口>
NO_PROXY=localhost,127.0.0.1,::1

它会保留 .env 里的其他键、在变更前创建带时间戳的备份,并使用原子写入;不会修改 config.toml。如果代理 URL 含有账号密码,状态输出也会隐藏凭据。

在出现问题的环境中,wss:// 请求会沿 HTTPS 代理解析,因此显式设置 HTTPS_PROXY 可以让 WebSocket 在网络恢复后重新走确定的代理路径。这里的目标是让 WebSocket 稳定重连,不是强制 Codex 改用 HTTP

五、完全退出并重新打开 Codex

仅关闭窗口通常不够。请完全退出 Codex,再重新打开,因为 Codex 需要在新进程启动时读取 ~/.codex/.env

重启后依次验证:

  1. 原有任务列表仍然可见;
  2. 正常发送一条请求,可以快速得到响应;
  3. 临时断开网络再恢复;
  4. 再发送一条请求,不再经历固定的五次重试;
  5. 日志不再出现本次测试对应的 WebSocket 五连重试。

为了观察代理是否稳定,可以做短时间连续探测:

for i in {1..10}; do
  date '+%H:%M:%S'
  curl -x http://127.0.0.1:<实际端口> \
    -sS -o /dev/null -w 'status=%{http_code} time=%{time_total}\n' \
    https://chatgpt.com
  sleep 3
done

重点看是否频繁连接失败、超时或耗时突然暴涨,而不是要求所有状态码都必须是 200。

六、如何回滚

执行 apply 时,脚本会打印备份文件路径。需要回滚时运行:

python3 scripts/configure_proxy_env.py restore \
  --backup ~/.codex/.env.bak-YYYYMMDD-HHMMSS-ffffff

如果原本没有 .env,只想移除脚本管理的三个键:

python3 scripts/configure_proxy_env.py remove

回滚后同样要完全退出并重新打开 Codex。

七、不建议优先尝试的方法

1. 为了关闭 WebSocket 新建自定义 Provider

有些方案会在 config.toml 中创建第二个 Provider,并设置类似 supports_websockets = false 的参数。它可能改变传输行为,但 Codex Desktop 可能按 Provider 身份区分或过滤任务,造成“历史任务不见了”的错觉。

为了保留登录状态和任务历史,不要把它作为首选修复。

2. 盲目添加 CODEX_*WEBSOCKET=false

这类环境变量可能因版本变化而无效,部分 Codex 构建还会过滤从 .env 载入的 CODEX_ 前缀变量。没有针对当前版本验证前,不要把它当作通用开关。

3. 反复清理缓存

如果根因是代理进程、系统代理或长连接恢复,清缓存通常不会解决问题,还可能增加历史状态风险。先查日志、监听端口和代理稳定性,信号更直接。

八、显式代理仍然无效怎么办

继续按以下顺序排查:

  • 是否同时运行了多个旧代理进程;
  • VPN/TUN 模式是否在网络恢复后卡住;
  • 系统代理是否仍指向旧端口;
  • 防火墙或安全软件是否拦截 WebSocket;
  • 公司网络是否做 TLS 检查;
  • DNS 是否在切网后短暂返回错误结果;
  • 当前代理节点是否支持稳定的 WebSocket 长连接。

如果普通网页正常、连续代理探测也稳定,但只有 Codex 仍五次重试,就保留相关日志并反馈给 Codex 支持渠道。本文方案来自特定 macOS、代理客户端和 Codex 构建上的实测,不应被理解为所有版本的官方通用配置。

总结

“浏览器已经恢复,但 Codex 仍重连五次”通常不是简单的断网,而是代理环境下的 WebSocket 路由恢复问题。最稳妥的处理顺序是:

  1. 从日志确认 responses_websocket 五连重试;
  2. scutillsof 找到真实代理端口;
  3. 通过 ~/.codex/.env 显式设置 HTTP/HTTPS 代理;
  4. 完全重启 Codex;
  5. 做一次断网恢复测试,并保留可回滚备份。

不要猜端口,不要先改 Provider,也不要在没有验证的情况下照搬禁用 WebSocket 的偏方。

参考


评论