feat: add global and per-provider upstream proxy settings#11
feat: add global and per-provider upstream proxy settings#11newcodebook merged 3 commits intolansespirit:mainfrom
Conversation
[P3] Proxy 配置变更语义不应在 Web API 层重复定义这次功能的整体目标我认同:把 upstream proxy 建模成“全局默认 + provider 覆盖”,并且用 我为什么认为这是个问题
这些都不是“接口层细节”,而是 provider proxy 配置语义本身 的一部分。 而同一套语义现在已经分散在多个层里:
这意味着,系统里关于 proxy 的“真实语义”已经不是只在一个地方定义了,而是开始同时存在于 config、API 和 runtime 多层里。 这样做的直接风险短期内这段代码当然是可工作的,但长期会有明显的维护风险:
我建议的最佳方案更稳妥的实现方式,是把 proxy 的 apply / normalize / validate 逻辑收敛到 可以考虑把它整理成类似这样的形态:
也就是说,职责应当是:
这么改的收益如果按这个方向收敛,会有几个明确好处:
结论所以这条评论不是在说“这段代码现在不能用”,而是在说:
在当前这个阶段,把 proxy 配置语义收敛到 |
[P2]
|
[P2] 相同的 effective proxy policy 没有复用 transport,会带来不必要的连接池割裂这次 runtime 层的落点整体是对的:不是在每个请求上临时判断 proxy,而是在构建 不过当前这里还有一个可以明显改进的实现点:虽然代码已经计算出了每个 provider 的 effective proxy policy,但对相同 policy 的 provider 并没有复用同一个 transport / client。 当前实现的问题在哪里从这段逻辑来看,流程大致是:
这意味着:
也就是说,当前代码虽然已经识别出“这些 provider 最终走的是同一套代理策略”,但并没有把这个结果真正用于 runtime 资源复用。 为什么这不是单纯的小优化这条不只是“代码还能更优雅”这么简单,它会影响 runtime 行为质量:
更稳妥的最佳方案这里更合理的实现方式,是按 effective proxy policy 复用 可以把 policy 作为 key 做缓存,例如按以下维度区分:
然后构建阶段变成:
这样会更贴合前面已经建立的抽象,也更符合 runtime 层真正关心的东西: 这么改的收益如果按 policy 维度复用 client,会有几个明确收益:
结论所以这条评论不是在否定当前实现方向,相反,我认为方向是对的;问题在于它还没有把“effective proxy policy”这个抽象贯彻到 runtime 资源复用层。 更好的形态应该是:
这样才能把这次新增的 proxy 模型真正落实成一个更合理的 runtime 实现。 |
Address PR lansespirit#11 review feedback: - Split global/proxy mode enums: global uses `environment|direct|custom`, provider uses `default|direct|custom` (no shared `inherit` value) - Move proxy apply/normalize/validate logic from web API into config layer - Share http.Client by effective proxy policy key for connection pool reuse
|
Fixed. |
[P3] Effective proxy policy 的判等仍然依赖未规范化的 URL 文本这次重构已经把之前几个更大的结构问题处理掉了:
这些方向我都认同,而且我认为是正确的改进。 问题具体出在哪里从当前实现看,policy 的形成和使用大致是这样:
也就是说,这个 key 现在不只是一个内部辅助值,它已经决定了两件非常实际的行为:
为什么这会出问题问题在于,当前 key 不是建立在“规范化后的 URL 语义”上,而是建立在“原始文本是否完全一样”上。 例如下面两种写法:
在网络语义上它们是同一个代理;
这意味着,系统在“请求实际会发往哪里”和“是否属于同一个 proxy policy”这两件事上,使用了不同粒度的判定标准。 这会带来什么实际影响这不是功能完全失效的 bug,所以我把它定成
为什么我认为应该在 config 层解决我不建议在 更自然的落点还是
所以延续当前重构方向,最一致的做法应该是:
我建议的最佳方案我建议把“canonical proxy URL”变成 config 层的一等能力,然后统一用于:
实现上可以有两种思路: 方案 A:在 apply 时直接存 canonical URL在
好处是:
代价是:
方案 B:保留用户输入,但额外提供 canonical accessor例如在 config 层增加类似:
内部通过 我更倾向这个方案,因为它把“显示/持久化的原始输入”和“内部用于判等的规范化值”分开了:
结论这条评论不是在否定这次重构,相反,我认为这次改动已经把 proxy 架构推进到了一个明显更好的状态。
如果把 proxy URL 的 canonicalization 再补齐,这套 proxy policy 抽象就会完整很多。 |
|
这次更新已经把 host 大小写和默认端口的 canonicalization 补上了,这个方向是对的;不过我再顺着 runtime identity / policy key 这条链路看了一遍,感觉这里还留了一个等价性边角问题。
虽然对“代理首跳是谁”这个语义来说是等价的,但现在仍会生成不同的 canonical 字符串。后面 如果这里的目标是按“实际 proxy 语义”而不是“配置文本字面量”来做去重,我觉得更稳妥的方案是把 proxy identity 在 config 层明确收敛成
同时建议补几组等价性测试,至少覆盖:
这样 canonicalization 的边界会更清晰,后面 policy key、client 复用和 reload state 继承也才能真正共享同一套“proxy identity”定义。 |
…comparison Add CanonicalProxyURL in config layer to normalize host case and strip default ports, so semantically equivalent proxy URLs produce identical policy keys. This ensures connection pool reuse and runtime state inheritance work correctly across reload even when URL text differs (e.g. host case, default port presence).
|
感谢这次持续跟进和多轮迭代修正,这个 PR 目前我这边已经重新完整审过一轮。 这次实现里,前面 review 提到的几个关键问题已经都处理到位了:
我这边本地重新跑了 所以这边决定接受并合并这个 PR。后续更彻底的 runtime identity / proxy policy 语义收敛,我们会作为维护者单独继续推进。 再次感谢你的贡献和配合修改。 |
有些中转站IP限制太严了,比如黑与白公益,我所有代理IP都被封了,只能直连;而有些公益站需要代理才能访问,需要单独配置代理。
所以添加了全局代理,以及每个provider设置单独代理: