Skip to content

探活用 new URL("/", apiBase) 丢掉路径前缀,带前缀的 apiBase 一定误报;断连报错也不含目标 host:port #111

Open

Description

@ExSchwi

环境

  • 插件:@mars-sea/dsh-commandcode-provider 0.16.0
  • 宿主:@deepseek-ai/dsh 0.2.1-rc.2(Windows 11 / Node 22.19.0)
  • apiBase 走本地反向代理并带路径前缀:http://127.0.0.1:18797/bili/https://api.commandcode.ai

问题一:探活丢掉了 apiBase 的路径前缀,带前缀的反代一定误报

probeCommandCode() 在 lib/index.js:9965,第 9969 行:

url = new URL("/", options.apiBase).toString();

而真实请求是纯字符串拼接,前缀会保留(lib/index.js:8568):

await this.fetchJson(`${apiBase}${path}`, ...)   // /alpha/whoami、/provider/v1/chat/completions ...

复现(本机实测):

console.log(new URL("/", "http://127.0.0.1:18797/bili/https://api.commandcode.ai").toString())
// → http://127.0.0.1:18797/     ← 前缀 /bili/https://api.commandcode.ai 被丢掉

后果:只要 apiBase 指向一个必须带前缀才路由的反向代理(bili、公司网关、/api/commandcode 这类子路径挂载都算),探活就会打到反代根路径而不是 Command Code 端点。根路径 404 时 probeOutcomeForStatus()(lib/index.js:9954,只有 2xx/3xx 算 ok)判为 http-error,界面显示连不上,而实际 /alpha/whoami 是通的;反过来根路径被别的服务占用并返回 200 时,又会假报 ok。

建议:探活复用与真实请求一致的拼接,用同一前缀下的轻量端点(例如 ${apiBase}/alpha/whoami),至少不要用 new URL("/", ...) 把路径裁掉。若确实要保持「只探根」,请在 README 写明,因为反代场景下它探的不是真实链路。

问题二:断连报错不含解析后的地址,只能盲猜

面板的 usageNetworkHint / errorNetworkHint(client.js:3292、client.js:7717)都是同一句:

所有请求都没有到达服务端。请检查网络连接或 API 地址设置。

配上四个 fetch failed,用户拿不到「插件实际往哪个 host:port 发了请求」这个最关键的信息。本次真实故障是反向代理换端口(18797 → 18798 → 18787),四个账户接口全部 ECONNREFUSED,但界面完全看不出来。

建议:网络层失败时带上解析后的目标地址(scheme://host:port,不带 query/token),例如「所有请求都没有到达服务端(目标 http://127.0.0.1:18797,连接被拒绝 / 超时)」,这样能把「代理没起」「代理换了端口」「API 真挂了」区分开。

说明

这两条都是代码层行为,与 DSH 宿主版本无关(0.2.1-rc.2 本身在此插件 engines.dsh 范围内)。

Activity

  1. ExSchwi commented on Oct 31, 2026

    @ExSchwi
    Author

    两个问题都改了,和 #110 在同一个 PR:#113

    问题一(探活丢前缀):probeCommandCode() 里的 new URL('/', options.apiBase) 换成新的 probeTargetOf(apiBase) —— new URL(apiBase) 之后只补尾斜杠,不再折回 host root。真实模型请求本来就是 ${apiBase}${path} 字符串拼接,所以探活目标也应该是配置的 base 本身;http://127.0.0.1:18797/bili/https://api.commandcode.ai 现在会去探 /bili/https://api.commandcode.ai/ 而不是 http://127.0.0.1:18797/。probeOutcomeForStatus() 的白名单没动:探到前缀根的 404 仍然算 http-error,但现在这个 404 是真从上游回来的,而不是自己构造出来的。

    问题二(失败串没有 host:port):getUsage() 里两处 failures.push(${path}: …) 改成 ${base.replace(/\/+$/, '')}${path},于是面板 detail 里是完整地址,例如 http://127.0.0.1:18797/bili/https://api.commandcode.ai/alpha/whoami: fetch failed。端口从 18797 漂到 18798 时,这条提示直接指出客户端试过的地址,不用再猜。usageNetworkHint / errorNetworkHint 的中英文案也改成说明这件事。

    验证:新增 probeTargetOf 单元测试、path prefix 与反向代理 prefix 两个探活测试、以及 getUsage 失败记录保留前缀的测试;npm test 全量 1148 项通过,npm run typecheck 与 npm run build 均正常。

  2. Mars-Sea commented on Oct 31, 2026

    @Mars-Sea
    Owner

    谢谢反馈,两个问题都已确认并修复。

    • 探活不再用 new URL('/', apiBase),改为请求 ${apiBase}/alpha/whoami,路径前缀会保留;探活不带凭据,所以未认证的 401/403 计为可达。
    • 网络层失败现在会带上原因与目标地址,例如「连接被拒绝(ECONNREFUSED);目标 http://127.0.0.1:18797」。

    已用真实宿主 + 带前缀反向代理复现并验证过,会随下一个补丁版本发布(当前尚未发版)。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions