Playwright 如何按域名分流?代理规则与浏览器配置实践
Playwright 按域名分流,可以让浏览器连接一个固定代理入口,再由入口根据目标主机选择直连或不同上游。 简单场景也可以使用浏览器已有的代理和绕过配置;只有需要多组规则、明确的匹配顺序与失败策略时,才值得增加应用自己的路由层。
多个账号的浏览器目录解决 Cookie、站点存储等会话隔离;域名分流解决连接路径。目录独立不等于出口不同,指定一个代理端口也不等于页面关联的所有请求都采用预期路径。
本文结合个人桌面工具 dyDM 的私有实现,统一以提交 56e25be7f9792a4245f343408bbb061df59bbf7e 为代码阅读基线。公开原理与原创教学示例供读者复核,私有项目的历史网络测试不作为本次重测结果。本文不提供完整生产代理服务,也不接管整机流量。
这里的实现对应开发源码,不表示正式安装包已经包含全部能力。2026年11月7日复核到的提交 895a6f9 已包含可选的本地代理拒绝连接后直连,差异在失败策略一节单独说明。
浏览器原生代理配置适合哪些场景
Playwright 网络文档提供浏览器级和 BrowserContext 级代理配置。一个会话始终使用同一个出口时,直接配置已经足够;需要独立会话时,再结合不同 Context 或持久化目录管理。
以下是配置形式示意,127.0.0.1:19090 是虚构端口,需要由真实可用的代理服务提供。代码没有实现代理,也不是执行后即可联网的完整程序:
1 | # Chromium Context 配置片段;browser 由调用方提供。 |
Chromium 默认让 localhost、回环及部分链路本地目标绕过代理。这里的 <-loopback> 用于取消这组隐式绕过规则,让访问本地目标的连接也进入案例的规则判断;它不是“绕过本地代理服务器”。这与 dyDM 的租约配置一致,尤其影响本地夹具验证。该语法针对 Chromium,不应直接推广到所有浏览器;是否代理本地资源应由应用明确决定。Chromium 的隐式绕过规则说明
如果只有少量“这些目标绕过代理”的条件,也应先评估原生 bypass 是否已经满足要求。不要把每个项目都写一个本地服务当作 Playwright 的必要步骤。
私有案例选择增加路由层,原因是它同时需要按账号引用规则组、支持精确例外和后缀规则、保留运行版本,并在命中代理却连接失败时返回错误。这些是应用约定,不能自动由一个地址输入框表达。
context.route() 则用于请求拦截、修改、模拟或继续处理 HTTP 请求,与建立通用 TCP 代理是不同层次。这里讨论的是连接下一跳,不是通过模拟响应改变页面内容。
用一次新连接理解本地路由入口
假设浏览器请求 https://www.example.com/article,需要新建连接。应用给浏览器的地址是本地 SOCKS5 入口,用户真正配置的上游则是另一个 HTTP 代理端口:
1 | 浏览器 |
SOCKS5 请求包含目标地址与端口;本地入口从中得到 www.example.com:443,并不读取 HTTPS 中的 /article。主机名如何编码、IPv4/IPv6/域名地址类型如何区分,见 RFC 1928。如果客户端交来的是 IP,当前案例不会通过反向 DNS 或 TLS SNI 恢复原始域名。
命中 HTTP 上游后,应用发送 CONNECT;上游接受隧道,再向浏览器报告 SOCKS5 连接成功。目标网站的 TLS 仍由浏览器完成,应用只转发字节,不安装解密证书。RFC 9110 的 CONNECT 定义用于支持这一协议解释,不能据此证明某个上游实际可达。
如果新连接的目标没有命中代理规则,应用可以直接连接目标。浏览器仍经过本地入口,入口之后的动作才是直连。 这与浏览器完全绕过本地入口不同。

图1:原创连接示意,描述一次新建 TCP 连接,不是抓包结果。
一个页面还会加载接口、图片、媒体和登录资源。这些连接使用各自的目标主机匹配规则,不能因为主页面属于 example.com,就假设另一个接口域名也会走同一个代理。连接复用还会影响新规则何时有机会参与选择。
规则先后顺序比名称更重要
规则组至少需要表达:匹配对象、启用状态、动作、优先顺序和未匹配动作。服务器与规则组采用稳定 ID,账号引用 ID,名称只用于展示;改名不应破坏绑定。
例如希望一个接口直连、其余子域走代理:
| 顺序 | 匹配条件 | 动作 |
|---|---|---|
| 1 | 精确域名 api.example.com |
直连 |
| 2 | example.com 本域及子域 |
代理 A |
| 未匹配 | 没有启用规则命中 | 直连 |
精确例外必须放在宽泛后缀前。后缀判断也要遵守标签边界:a.example.com 属于该后缀,notexample.com 不属于。
下面是独立教学示例,只支持精确域名和域名后缀,输入限制为合法 ASCII 域名;不是从私有项目复制的完整匹配器。将它保存为 rules_example.py,运行 python rules_example.py:
1 | def choose_action(host, rules, fallback="direct"): |
真实实现还需在保存阶段校验类型、目标引用、ID、端口及域名,处理 IDNA 和 IP 字面值,并让预览与运行时复用同一套匹配逻辑。不能把未校验数据直接交给示例函数,再把错误解释成默认直连。
未匹配直连与代理失败直连是两种策略
未匹配动作是用户事先选定的规则;命中代理后再改为直连,则是连接失败时改变了路径。
1 | 没有规则命中 → 执行该组的未匹配动作 |
私有案例选择第二种情况不尝试直连。这个结论只描述应用中对应连接分支的行为,不能扩大成浏览器或系统所有网络路径都获得了相同保证。
上述流程和图2对应 56e25be 基线。后续开发版本(核对至 895a6f9)允许对单个本地代理明确开启 direct_on_local_refused:旧配置缺失该字段时保持关闭;只有代理地址为回环 IP、连接代理自身端口明确被拒绝,且尚未发送代理协议数据时,才尝试一次直连目标。远程代理、连接超时、认证或 CONNECT 拒绝、证书错误,以及连接建立后的故障,都不触发这一例外。每个新连接仍先尝试原代理,不会永久切换到直连。
回退采用系统路由,实际出口可能是本地网络,也可能受 VPN 或其他隧道影响,不能保证仍使用指定代理出口。需要固定代理出口时应保持关闭;此选项也不表示应用会自动重放已经提交的业务操作。
配置缺失和配置损坏也要区分。缺少整个配置段,可以按明确的初始约定创建默认组;已经存在却解析失败、格式版本未知或引用不存在时,应阻止相应启动并提示修复。把两者都处理成空字典,会让一个配置错误悄悄变成路径选择。

图2:原创规则示意;图中域名、动作和服务器名称均为教学数据。
PAC 也需要分别检查脚本获取失败、旧脚本重新获取和返回代理不可达等条件。Chromium 代理文档描述了这些机制及条件差异。案例中的历史 PAC 反例解释了项目取舍,但不构成“PAC 在所有环境都不可靠”的结论。
保存新规则为什么不改变旧浏览器
案例采用启动快照:浏览器启动时读取账号最新绑定,校验规则,固定配置版本,取得对应本地入口,然后再创建浏览器。已运行的浏览器继续使用自己的版本,新启动的浏览器才采用保存值。
这样可以避免一个正在运行的任务在新旧路径间突然切换。它不是热更新的唯一设计;如果产品确实需要立即切换,应另外处理已有连接、重试、任务状态和用户确认,不能把“保存成功”直接等同于所有连接已更新。
默认组表示账号没有单独绑定时继承哪个组;未匹配动作表示当前组没有规则命中时怎么办。默认组同样可以包含代理规则,不能把“默认”当作“直连”的别名。
浏览器会话也不应因为继承规则而复制。重新登录可以继承原账号的规则来源,同时使用独立候选目录;规则归属与 Cookie 归属分别管理。
验证入口、上游和出口需要不同证据
| 检查 | 可以支持的结论 | 仍不能证明 |
|---|---|---|
| 浏览器访问本地专用探针并返回正确版本 | 到达预期入口和快照 | 远端代理可达 |
| 上游夹具收到连接,目标端记录对应请求 | 指定连接经过该上游 | 所有页面子资源都被覆盖 |
| 关闭上游后,目标端没有收到绕过请求 | 已测失败路径未转直连 | 系统全部流量都无法绕过 |
| 指定检测接口返回预期地址 | 该次接口请求的出口符合预期 | WebRTC、其他应用和 DNS 路径相同 |
“页面返回 200”可能来自代理,也可能来自直连,不能单独证明规则有效。排查 IP 不符时,应先确认实际检测接口的域名、当前快照和命中规则,再检查上游出网与其他网络路径。
当前案例的本地服务处理 TCP,不实现 SOCKS5 UDP ASSOCIATE,不自动接管 Python 下载或整机网络。WebRTC 的限制与验证需另行进行,可先参考已有的 WebRTC 泄漏机制文章。
本地入口还增加了应用自身的资源责任:监听器、并发连接、握手和空闲超时、DNS 查询、取消和退出都需要管理。只绑定回环地址,也不等于获得本机用户隔离。本文介绍连接模型和规则约定,不声称私有实现已完成打包环境及长期压力验证。
参考资料
资料核对日期为2026年11月6日。前述规则示例为作者原创;私有案例仅提供脱敏机制描述,不以内部链接充当公开证据。
- Playwright:HTTP Proxy,代理配置层次。
- Playwright:BrowserContext,会话与初始化能力。
- Chromium:Proxy support in Chrome,浏览器代理和PAC行为。
- RFC 1928:SOCKS5,目标地址、命令及协议边界。
- RFC 9110:CONNECT,HTTP隧道语义。