Chrome 自某个版本开始,移除了对 pac file:// URL 的支持,至此只剩下 HTTP 能用了。本地 pac 文件用不了,还得给丢到 http 服务上,单独部署维护多麻烦,那么就写个本地专用的 pac 服务器好啦!

系统代理设置 PAC 脚本,用以自动分流浏览器和套壳浏览器应用的请求,爬墙好手大概对这个操作都很熟悉。pac 本身只是个简单的 js 脚本,系统设置里写好地址,浏览器就会拿普通 http 去请求到 pac。至于拿 gfwlist 自动生成 pac、自动更新等等操作,早在 ss 时代就已集成了。

自转向使用 v2ray 后,我只使用 v2ray-core 一个 exe 后台运行代理,它本身没有 pac 相关功能,所以我原本会在本地放一份 pac 文件,然后系统代理设置的脚本地址手动写成 file:///c/users/auto.pac 的形式,让浏览器直接访问本地文件。chrome/chromium 移除 file:// 的支持后,图方便我把 pac 丢到了本网站服务器上,能用但是延迟高,导致打开国内网站都会经常卡住,一直在等 pac 请求完。直到今天 ———— 忍不了造个轮子出来啦!

程序很简单,就一个 pacserver.exe,把 pac 文件命名成 autoproxy.pac 后放到跟 pacserver.exe 同一个文件夹里。运行以后,pac 地址固定为 http://127.0.0.1:9123/autoproxy.pac,设置成系统自动代理地址。至于启动,可以跟 v2ray.exe 一样,用 vbs 脚本后台运行:

createObject("WScript.Shell").Run "c:\v2ray\pacserver.exe",0

pacserver.exe 点此下载,使用 Python3.7 编写,PyInstaller 打包,所有源码如下,五十行不到就搞定咯:

import http.server
import os

PACFILE_NAME = 'autoproxy.pac'
PACFILE = None
PORT = 9123


def prepare_pac():
    global PACFILE
    dir = os.path.dirname(os.path.abspath(__file__))
    os.chdir(dir)
    with open(PACFILE_NAME, 'rb') as f:
        PACFILE = f.read()


class PacRequestHandler(http.server.SimpleHTTPRequestHandler):
    def do_GET(self):
        if self.client_address[0] not in ('::1', '127.0.0.1', 'localhost'):
            return
        if self.path != '/' + PACFILE_NAME:
            return
        self.send_response(200)
        self.send_head()
        self.wfile.write(PACFILE)


def main():
    prepare_pac()
    http.server.ThreadingHTTPServer(("127.0.0.1", PORT), PacRequestHandler).serve_forever()


if __name__ == '__main__':
    main()