前言¶
DSH 的理念是插件化,插件和模型调用经常要访问外部 HTTP/HTTPS 接口。实际运行中,目标地址、provider、plugin 可能不同;有的请求需要直连,有的请求需要走代理;直连失败时还需要安全地换到代理。
dsh-system-proxy 把这类出站路由放到 DSH host plugin 层处理,避免每个插件各自拼接代理逻辑。
这是什么¶
dsh-system-proxy 是一个 DSH host plugin,用于在 DSH 主进程中统一处理出站 HTTP/HTTPS 路由。仓库地址所有者为 khiqwq,源码仓库是 https://github.com/khiqwq/dsh-system-proxy。
它解决的核心问题是:
- HTTP、HTTPS、SOCKS4、SOCKS4a、SOCKS5、SOCKS5h 代理;
- 多个具名代理(named proxies);
- 按
host、provider、plugin路由; direct、proxy、fallback、block四种动作;- 直连失败或延迟过高时使用代理保底;
- 每目标 EWMA 延迟、失败冷却(cooldown)与健康记忆;
- 显式
provider/plugin上下文,不伪造调用方身份; - 代理凭据脱敏、安全日志和热重载恢复;
- 包装
globalThis.fetch; patchNodeHttp: true时包装node:http/node:https的request与get;- 内网 / 云元数据端点的默认保护;
- 交互式配置卡;
passwordRef/credentials保存密码。
运行要求 Node >=22。
核心能力¶
路由动作¶
插件把出站请求归到四类动作:
direct:只直连。proxy:强制使用指定具名代理。fallback:先直连,满足条件时改用代理。block:本地拒绝请求。
引用不存在或当前不可用的代理名会报 UNKNOWN_PROXY,不会静默降级直连。
fetch 与 node http/https¶
插件会包装 globalThis.fetch。配置中启用 patchNodeHttp: true 时,还会包装 node:http / node:https 的 request 与 get。
这是进程级全局补丁。同一进程内不应同时加载多个相互竞争的传输包装插件。
provider / plugin 上下文¶
全局 fetch 本身不能可靠判断请求来自哪个插件。调用方需要显式提供上下文:
await ctx.networkRoute.run({ provider: 'openai', plugin: 'my-plugin' }, () => fetch('https://api.openai.com/v1/models'))
对于流式响应,可以用 iterable 包装惰性异步迭代器:
const attributed = ctx.networkRoute.iterable({ provider: 'openai' }, response.body)
这样在消费 response.body 时,可以保留 provider / plugin 归属。
安全与回退¶
自动回退不是普通重试。默认只允许 GET、HEAD、OPTIONS、TRACE 自动换路;POST 默认不重放。
以下情况不重放:
- 流式上传;
FormData;- 超出缓冲上限的
body; - 用户主动
abort; - 已经收到响应头或 SSE 字节;
- 无法证明请求字节尚未写出的连接后失败。
只有连接前失败才安全换路。主动健康探测默认关闭。
内网与云元数据保护¶
安全默认让 localhost、loopback、169.254.0.0/16、云 metadata 端点、RFC1918 内网和 IPv6 ULA 一律直连。内网和云 metadata 流量因此保持直连,不会被交给外部代理。
密码与凭据¶
插件支持 passwordRef / credentials 保存代理密码。密码仅通过单向 credentials.set() 提交,绝不会保存到 settings;保存后密码草稿立即清空。
trustRouteHeaders 默认关闭;内部路由控制头会在发出请求前自动剥离。
SOCKS 限制¶
SOCKS4 / SOCKS4a 面对 IPv6 目标时,会在握手前显式抛错 SOCKS4_IPV6_UNSUPPORTED,不会静默直连。
安装与启用¶
发布后可在对应 profile 中安装:
dsh plugin --profile <name> add dsh-system-proxy
运行环境需要 Node >=22。
安装前应检查源码与许可证,并确认插件以当前 dsh 进程权限运行是否符合预期。
配置与覆盖¶
配置位于 profile 的 cordis.patch.yml。基本结构是:
proxies是对象,用来声明多个具名代理;rules是数组,用来描述路由规则;default是对象,用来声明默认策略。
Loader 配置是整体替换:增加一条规则时,必须重述完整 config,不能只写增量字段。
环境变量可用于覆盖或禁用:
DSH_PROXY_URL
DSH_PROXY_MODE
DSH_PROXY_DISABLE
NO_PROXY/no_proxy
适用场景¶
适合以下情况:
- 在 DSH 中统一处理出站 HTTP/HTTPS 请求;
- 按目标主机、provider、plugin 选择直连或代理;
- 直连优先,并在连接前失败时回退到代理;
- 保护
localhost、loopback、云 metadata 和 RFC1918 内网地址不被外部代理转发; - 需要为代理密码使用
passwordRef/credentials,而不是把密码写入 settings。