先把概念讲清楚:PAC 是什么,它解决了什么问题

想象你在一条路上开车,有些路段要走收费高速(代理),有些路段可以走免费国道(直连)。PAC(Proxy Auto-Config)就是一张“路线表”,以代码的形式告诉你的电脑或浏览器:到这个域名或 IP,走代理;到那个域名,直连。
它能解决的主要场景:
- 把特定网站(例如境外服务)走代理,而本地或敏感服务走直连,避免全部流量穿越代理导致延迟或带宽浪费。
- 在公司或家庭网络里对不同目的地做灵活分流,兼顾速度和隐私。
- 当代理有多个出口时,根据目标智能选择最快或最合适的出口(结合客户端/服务端能力)。
PAC 的工作原理(简明)
PAC 文件其实是一个以 JavaScript 写的小函数——FindProxyForURL(url, host)。当浏览器发起请求时,系统会调用这个函数并传入目标 URL 与主机名,函数返回字符串,例如:
- “DIRECT”:表示直连;
- “PROXY 127.0.0.1:1080″:表示通过指定代理;
- “PROXY 1.2.3.4:8080; DIRECT”:表示先尝试代理,不通则直连。
函数可以用内置辅助函数做判断,比如 dnsDomainIs(host, “.example.com”)、shExpMatch(host, “*.google.com”)、isInNet(host, “1.2.3.0”, “255.255.255.0”) 等。
常见内置函数与含义
- dnsDomainIs(host, domain):检查 host 是否以 domain 结尾(适合后缀匹配)。
- shExpMatch(str, shexp):shell 风格通配符匹配(* ?)。
- isInNet(host, pattern, mask):判断 host 的解析 IP 是否在指定网段。
- myIpAddress():返回客户端本机 IP(有时非可靠,取决于环境)。
- dnsResolve(host):把域名解析为 IP(可能阻塞,且受本地 DNS 缓存影响)。
如何写一个高效且稳健的 PAC 文件
用费曼法来讲,就是把复杂问题拆成最小的判断步骤,并且每步都能被简单解释。写 PAC 时,遵循几个原则:
- 规则由具体到泛化:先匹配最常访问或最重要的网站,后匹配通配或默认规则,避免经常误命中。
- 尽量少用正则:正则与大量字符串操作会减慢脚本运行,PAC 在每次请求时被调用,效率很重要。
- 谨慎调用 DNS 解析:dnsResolve 会阻塞并受缓存影响,频繁调用会带来性能和准确性问题。
- 返回结果尽量简短:多个代理可以用分号隔开,但顺序会影响连接尝试顺序。
一个典型的 PAC 示例
下面给出一个常见场景:指定域名走代理,本地和公司内网走直连,其他默认走代理。
function FindProxyForURL(url, host) {
// 本地回环和保留地址直连
if (shExpMatch(host, "localhost") || shExpMatch(host, "127.*") || shExpMatch(host, "10.*") || shExpMatch(host, "192.168.*")) {
return "DIRECT";
}
// 内网域名直连
if (dnsDomainIs(host, ".intranet.example.com")) {
return "DIRECT";
}
// 常用外网服务走代理
if (shExpMatch(host, "*.google.com") || shExpMatch(host, "*.youtube.com")) {
return "PROXY 127.0.0.1:1080";
}
// 其它全部走代理
return "PROXY 127.0.0.1:1080; DIRECT";
}
规则写法快速参考表
| 场景 | 函数/写法 | 说明 |
| 域名后缀匹配 | dnsDomainIs(host, “.example.com”) | 匹配 example.com 及其子域名 |
| 通配符匹配 | shExpMatch(host, “*.google.com”) | 比 dnsDomainIs 更灵活,可用于复杂模式 |
| IP 网段 | isInNet(host, “1.2.3.0”, “255.255.255.0”) | 判断解析后 IP 是否在指定网段 |
| 组合策略 | return “PROXY a:1; PROXY b:2; DIRECT” | 按顺序尝试代理,失败再尝试下一项 |
部署与在快连加速器中应用(通用步骤)
不同客户端具体 UI 名称可能不同,但通用流程是:
- 把 PAC 文件放在静态 HTTP 可访问位置(本地服务器或外网 HTTP 地址)。
- 在快连加速器客户端或系统代理设置里选择“自动代理配置”或“PAC 模式”。
- 填入 PAC 的 URL(例如 http://192.168.1.2/proxy.pac)。某些客户端支持粘贴脚本内容或上传文件。
- 保存并启用,观察客户端状态指示:客户端通常会显示已启用 PAC 或正在使用自动代理。
- 测试(见下一节),如果规则不生效,检查 PAC 文件是否能通过 HTTP 访问并且 Content-Type 正确(text/plain 或 application/x-ns-proxy-autoconfig)。
针对常见平台的注意点
- Windows:系统代理设置支持 PAC,某些应用可能绕过系统代理。可以用 Internet Options 或 netsh 来设置。
- macOS:在网络偏好设置里配置自动代理,PAC URL 填入“自动代理配置”处。
- iOS:在 Wi-Fi 的代理设置里可以填写 PAC URL,但移动数据下部分应用不遵循系统 PAC。
- Android:原生对 PAC 支持有限,许多第三方加速器客户端内置 PAC 选项;WebView/系统浏览器的表现也因设备而异。
测试与排障清单(务必逐项验证)
配置完 PAC 后不要寄希望一次到位,按下面流程逐项验证:
- 能访问 PAC 文件:在浏览器打开 PAC URL,看是否返回脚本内容,且 Content-Type 合理。
- 函数执行是否被调用:用浏览器开发者工具观察网络请求走向,或在 PAC 中临时加入容易触发的规则来验证(谨慎不要留下调试代码)。
- DNS 泄露检查:如果 PAC 使用 isInNet 或 dnsResolve 判断 IP,要确认解析所用的 DNS 是否为本地或代理端的 DNS,避免敏感域名被本地 DNS 解析泄露。
- 缓存问题:系统/浏览器会缓存 PAC 文件和 DNS,修改 PAC 后可能需要重启浏览器或清缓存来强制刷新。
- 顺序错判:如果某些域总是走错路径,检查是否有早期泛规则把它匹配走了,按具体->泛化顺序重排规则。
性能与安全考量:别把 PAC 写成慢脚本
PAC 每次请求都会运行(或在短期内被缓存和复用),因此:
- 避免在 PAC 中做大量正则或阻塞性的 DNS 查询。
- 不要把大规模黑名单/白名单放在 PAC 脚本里;若规则很多,考虑把决策移到本地代理或服务器端,然后 PAC 只处理少量快速判断。
- 注意隐私和日志:走代理的请求会被代理记录,尤其是把全部流量走代理时。
示例:用 isInNet 做 CIDR 判断的小技巧
PAC 没有直接写 CIDR 的语法,但可以用 isInNet + mask 来达到效果。例如判断 10.0.0.0/8:
if (isInNet(host, "10.0.0.0", "255.0.0.0")) return "DIRECT";
但注意 isInNet 依赖 dnsResolve 或系统 DNS,若 host 是 IPv6 或解析失败则不可靠。
常见错误与坑
- PAC 文件返回 404 或被缓存:客户端不会提示详细错误,导致不起作用。确保 URL 可访问并检查 HTTP 响应头。
- 不同应用对系统代理的支持不一致:一些应用(比如部分视频客户端或游戏)绕过系统代理,PAC 无效。
- 循环调用:PAC 中调用 dnsResolve 并在失败时触发新的网络请求可能导致奇怪循环,避免复杂依赖。
- 代理链与失败顺序误解:多代理写成 “PROXY a; PROXY b; DIRECT” 是按序尝试的,不是并行。
进阶:动态 PAC 与分流策略结合
如果你想更智能,可以结合后端服务生成 PAC 文件:
- 服务器端维护大型黑/白名单并按地区、时间或用户策略动态生成 PAC,客户端只拿到简洁决策逻辑,减少运行开销。
- 也可以把 PAC 配合本地代理管理器使用:PAC 负责粗分流(哪些域走代理),本地代理再负责更精细的出口选择、测速与重试。
调优建议(实战)
- 首先明确目标:是为了速度、节省带宽还是访问不可直连站点?目标不同规则差别很大。
- 把高频访问的外网域名单独列出为走代理,防止每次请求都触发复杂判断。
- 把本地和保留地址放最前面,避免误判成需要代理。
- 尽量在非高峰时进行大规模改动并逐步回滚测试,观察用户反馈。
好了,以上就是把 PAC 当成“路由员”来理解并实操的整套思路:用简单的判断先把常见场景挡在外面,避免每次都做重计算;把复杂规则交给更有存储与计算能力的一端(服务器或本地代理);测试时重视 DNS 与缓存的表现。实践中你会发现,PAC 配置是不断迭代的过程,先从简单规则开始,慢慢扩展,最终既满足访问需要又不会拖垮客户端性能。
