Skip to content

v2.1.0-go

Choose a tag to compare

@github-actions github-actions released this 18 Sep 02:47
· 93 commits to go-rewrite since this release

v2.1.0-go

一次以并发正确性与运维健壮性为主的版本:修掉五处会在生产上造成实际损失的
缺陷,加固验证码浏览器路径,并补上 OpenAI Responses 的用量细节。因为其中有几处
改变了对外可观察的行为(见下),故按次版本号发布。

行为变更

  • 客户端无法再覆盖网关的固定请求头。此前固定头先建立、客户端透传头后合并,
    客户端送一个 X-Device-Mid 就能改掉该账号的设备指纹——而这正是每账号指纹隔离
    的基础;大小写不同的两个同名头还会各占一个 map 键,最终取值取决于迭代顺序。
    现在固定头恒胜:透传头先合并(键统一为规范形式),固定头最后覆写。
    ⚠️ 客户端不能再影响 X-Device-Mid、Anthropic-Version、Content-Type 等取值。
  • 客户端断连不再冷却账号。此前上游请求被取消(用户关掉客户端、连接中断)会
    按「连接失败」把账号冷却整整一轮冷却时长,一次中断最多可连锁影响 5 个账号。
    现在识别为取消:不冷却、也不换号(换号只会白烧另一个账号的额度)。
  • 异步(空闲池)路径开始识别 200 包装的业务错误。上游会用 200 包装额度耗尽
    一类的业务错误(如 code=1005),此前异步路径直接当成功流转发:客户端收到空流、
    账号不被标任何状态、下次仍会被选中白耗。现在与同步路径走同一套分类。
  • 收到 SIGTERM 会优雅停机。此前进程不处理停机信号,容器要等约 10 秒被强杀,
    额度监控与领取调度器都来不及收尾;错误路径的 os.Exit 还会跳过全部 defer。
    现在停止接受新连接、等待在途请求收尾(上限 10 秒)后退出。
    ⚠️ zcode2api 的退出码语义随之明确:0 为正常退出(含收到信号),1 为启动失败。
  • /v1/responses 的 usage 口径变化。input_tokens 现在并入缓存读写
    (Anthropic 把缓存 token 单列在 cache_read_input_tokens /
    cache_creation_input_tokens,不计入 input_tokens),并新增
    input_tokens_details.{cached_tokens, cache_write_tokens}。此前只报原始
    input_tokens,用量会被严重低估,且按 cached_tokens 判断上下文压缩时机的
    客户端(如 Codex)会一直以为没有缓存命中。

修复内容

网关

  • 额度信号不再改写更强的账号状态。invalid(凭证失效,需人工介入)、
    cooling(冷却窗口内)、disabled(管理员主动停用)三者与「额度用没用完」无关,
    此前会被 MarkModelExhausted 无条件刷成 active 并清空冷却时间——并发下一条 402
    就能把刚判失效的账号放回轮询。现在只更新模型耗尽清单,不动账号状态与冷却窗口。
  • 异步路径的 200 + JSON 分类与同步路径逐条对齐(1005 → 标该模型耗尽并换号;
    3007 → 换令牌重试;其余业务码 → 投递错误事件;无业务码 → 判为无效流)。

运维

  • HTTP 服务端补上 ReadHeaderTimeout(30 秒)与 IdleTimeout(120 秒)。
    WriteTimeout 保持为 0——SSE 是长连接,写超时会把正常的长流掐断。

验证码

  • 浏览器池的启动与关闭移出求解器锁。此前 pool.Start()(最长 90 秒)持锁执行,
    期间所有求解者、乃至停机时的 Close() 全被钉住——后者会让容器等不到优雅退出。
    并发冷启动由「启动中」闩串行化,仍只拉起一个浏览器进程。
  • 连接浏览器失败时不再对未连接成功的对象调用 Close()(上游把这一处判定为
    nil panic 风险),资源清理由 launcher 负责。
  • 解包 tar 的硬链接分支补上路径逃逸检查(符号链接分支原本已有)。此前未校验的
    Linkname 可把解包目录之外的任意文件内容复制进来。顺带修掉一处平台差异:
    filepath.IsAbs("/etc/passwd") 在 Windows 上返回 false(缺盘符),会让校验结果
    随平台漂移。
  • ZCODE_CAPTCHA_TIMEOUT 补下界(与同组其它超时项一致),设 0 或负数不再导致
    每次求解的 deadline 立刻到期。

OpenAI 兼容

  • function_call_output 现在同时接受字符串与内容块数组。Codex 在工具返回结构化
    内容时会发数组,此前只做字符串断言会把整段工具输出静默变成空串,多轮工具上下文
    随之丢失。
  • 流式 usage 合并改为数值取较大者,不再让 message_delta 补发的
    input_tokens: 0 把已统计的用量清零。

使用说明

升级只需重启进程;没有新增配置项,现有数据卷与 .env 均无需改动。

反代部署多了一条建议:若前面挂了 Nginx / Caddy 等反向代理,请把 compose 的端口
改成只绑回环(- "127.0.0.1:3000:3000")。反代转发后 RemoteAddr 恒为代理地址,
后台登录的「单 IP 10 次失败」限速会退化成全局限速——任何人的十次失败都能锁死整个
后台。README 与 docker-compose.yml 注释里都写了这一条。

客户端兼容说明

Docker

docker pull ghcr.io/fujunchao/zcode2api-plus:2.1.0-go

支持 linux/amd64 和 linux/arm64,同时更新 latest。现有数据卷与非 root 运行
方式不变。

能力依据

本版的改动全部来自与上游仓库的逐项比对(评估报告见
docs/upstream-sync-2026-09-18.md,实施记录见 docs/upstream-followup-plan.md)。
上游默认分支 go-rewrite 自 2026-09-12 分叉后新增 49 个提交,其中 18 个属一次
缺陷审查批次。我们只回移了判定为「确有影响」的部分;访客投稿、Cap 校验、
裸机部署脚本等与我们定位不符的改动未跟进。

验证情况:go build、go vet 与全量 14 个包测试通过,gofmt 74 个文件 0 不合规,
windows/darwin/linux 交叉编译通过。仍未验证或未覆盖的部分:

  • 并发正确性只在本机做了一半——本机没有 C 编译器,go test -race 由 CI 负责,
    其中验证码求解器的加锁改动最需要它把关。
  • 验证码浏览器路径没有实机跑通(本机无浏览器环境),相关改动只做了通读、编译与
    既有用例不回归。
  • 反代端口只绑回环是建议而非自动生效,需按自身部署调整 compose。
  • 2.0.8-go 起的那项领取链路修复(手动领取补当日活跃上报)仍未经过线上真实账号
    验证
    ,若领取仍报「上游無投放套餐」,问题在自造 device_mid 上。