在配置文件里,PAC 文件的地址和代理端点看起来可以互换,其实不能。一个是必须针对每个 URL 求值的策略程序,另一个是接受连接的 host 和 port。curl 只理解后者。把 PAC 地址传给 --proxy 是范畴错误,失败方式很迷惑,通常是对某个 Web 服务器长时间 CONNECT 超时之后。

两者到底是什么

你手上的东西它是什么curl 拿它做什么
http://wpad.corp.example/proxy.pac针对给定 URL 返回代理或直连的 JavaScript把它当文件取回来,然后就到此为止
http://proxy.corp.example:8080一个接受代理请求的监听端口会使用它,包括对 HTTPS 目标发起 CONNECT

这一点在 curl 常见问题 里说得很直白:curl 不提供 JavaScript 或 PAC 解释。套在 curl 外面、懂 PAC 的包装可以实现,但 curl 本身不行,也没有任何开关能把它变成浏览器。

为什么浏览器可以而 curl 不行

浏览器会与系统代理配置集成,取回 PAC 文件,并针对你打开的 URL 执行其中的规则。这个求值正是 PAC 文件提供的服务,它发生在浏览器内部,而不是你的终端里。

用 curl 下载 PAC 文件只会拿到它的文本,并不会让 curl 执行策略;而手动阅读以找出代理,是同一求值过程的手工版本,选错分支的概率也一样。真要读,请读与你的 host 匹配的那条 return 语句,而不是文件里第一个代理名。多数 PAC 文件包含好几个代理,只有一条分支适用于你。

对于已获批准的 HTTP 代理和已获批准的 HTTPS 服务,一个示意性请求是:

curl --proxy http://proxy.corp.example:8080 https://service.example.net/status

第一个地址是代理监听端点,第二个是你要访问的服务。这些只是示例端点,并不是谁实际做过的测试,请换成你所在组织的 scheme、port 与认证流程。

为这个目的地挑选代理

要问管理员的是:策略为你要访问的 URL 选了哪个代理,而不是组织拥有哪个代理。PAC 规则可能对内网服务、公开站点和故障切换情形给出不同结果,今天匹配你 URL 的规则,改过一次之后可能匹配另一个。

如果工作流需要不止一个已知请求,就用管理员支持的静态设置,或已获批准且懂 PAC 的集成。把复制来的一个地址硬编码进去,只能撑到策略改变、且没人记得为什么当初选了这个地址的那一天。

接下来看看 curl 继承了什么。代理环境变量和 NO_PROXY 都可能覆盖或排除你传入的代理,而一条匹配目标的排除规则会悄悄让请求走直连。要保留原本意图的策略,而不是删掉所有排除项,或强行让所有流量都走一个地址。用 -v 跑一次请求,看看它实际连到了哪个地址。

把两个 TLS 身份分清楚

使用 HTTPS 代理时,会有两条 TLS 连接参与:你到代理的连接,以及代理到目的地的连接。两者各有自己要验证的身份,关掉其中任何一个的验证都不是 PAC 的修复,而是在第一个问题之上又加了第二个问题。

保持验证开启,并读懂你得到的失败。代理认证挑战、代理不可达,以及网站拒绝,是三种不同结果,只有第一种与凭据有关。VPN 仍须提供通往私有代理的获准路径,包括代理主机本身的名称解析,这一切才可能成功。

把端点、scheme、port、认证方式、排除项,以及通往代理的 VPN 路径都记下来。正是这份记录让下一次请求可复现,也区分了了解你的代理和对着它猜。

相关文章