天天看點

代理自動配置檔案PAC的使用方法

我通常上網使用兩個浏覽器,safari用于一般上網;Chrome安裝SwitchyOmega插件,在不同的代理中切換,來保證某些網站的上網速度。

但是這種方式到了手機上就有點懵,幾乎所有的iPhone浏覽器都不支援代理的自動切換和設定,是以隻能選一個相對相容性比較好的網絡方式一直用下去。很不爽利。。。

後來發現代理自動配置檔案PAC是個好東西,跟SwitchyOmega類似,能夠比較智能的切換所需,是以給大家推薦一下。

通常裝置上網的設定,都有3個選項,1是直接連接配接,不使用代理;2是自行設定http代理;3是使用代理自動配置檔案URL。

這個URL指向的就需要是一個PAC檔案。如果在電腦上,可以是file:///這種形式指向本地的檔案。如果是手機上,則隻能放到一個可以http通路的伺服器上。

PAC檔案本質是js的一個子集,其中必須實作一個函數:

function FindProxyForURL(url, host)
           

兩個參數,url是将要通路的網絡位址,host是從url中分離出來的主機名。

每次浏覽器通路任何一個網址的時候,都會調用這個腳本,根據腳本的傳回值,選擇浏覽器使用哪個代理來通路網際網路。

FindProxyForURL函數傳回的通路方式,可以支援三種:

DIRECT
	直接通路,不适用任何代理
PROXY host:port
	設定http代理,host是代理主機,port是代理端口
SOCKS host:port
	使用SOCKS代理模式,後面是主機及端口号
           

這三種方式,前兩種是所有浏覽器都支援的。第三種SOCKS,有的浏覽器會解釋為SOCKS5,有的浏覽器會解釋為SOCKS4,還有的浏覽器還另外提供了SOCKS5方式。在mac Safari浏覽器上及iPhone中是将SOCKS解釋為SOCKS5協定。

對于PAC所使用的js語言的文法,不同浏覽器的支援也不一樣。IE支援完整的js文法,甚至alert指令彈出視窗都支援。Safari則嚴格遵循PAC的規範,僅支援簡單局部變量的指派和if語句及return語句。

是以通常安全起見,如果你的PAC檔案會用在很多場合,最好考慮相容性然後再編寫。

PAC所支援的函數并非通常浏覽器中的函數,詳細内容可以參考這個網址。

具體PAC腳本的編寫方法我們參考完成的腳本來解釋:

function FindProxyForURL(url, host)
{
    url  = url.toLowerCase();
    host = host.toLowerCase();

    if (shExpMatch(url,"*twitter*")  ||
        shExpMatch(url,"*facebook*") ||
        shExpMatch(url,"*fb*") ||
        shExpMatch(url,"*messenger*")) {
	        return "PROXY 192.168.1.1:8080; DIRECT";
		};
	
    if (shExpMatch(url,"*youtube*") ||
        shExpMatch(url,"*google*")){
	        return "PROXY 192.168.1.2:8080; DIRECT";
		};
		
    if (shExpMatch(url,"*wikipedia*") ||
        shExpMatch(url,"*blogspot*") ||
       ){
        return "PROXY 192.168.1.3:8080; DIRECT";
    }
    return "DIRECT";
}
           

shExpMatch是PAC專用的函數之一,判斷url中是否包含某個網址,"*"是通配符的意思,表示url兩端可以有任意字元,隻要中間部位比對成功即可。3組條件各自傳回一個代理,都不能比對,使用DIRECT直連。

PROXY 192.168.1.1:8080; DIRECT

是用分号隔開的兩個代理模式,如果前面的代理協定本浏覽器不支援的話,使用後面的協定。

是以類似SOCKS的協定,可以寫成:

SOCKS5 192.168.1.1:8081; SOCKS 192.168.1.1:8082; DIRECT
           

這表示如果浏覽器支援SOCKS5指令,則使用第一個協定;如果不支援SOCKS5指令,使用第二個SOCKS協定,實際在iPhone這就代表SOCKS5;前面兩個都不支援,則DIRECT。

PAC中支援的函數有好幾個,另外兩個可能常用到的是:isInNet和dnsResolve,來看一個例子:

if (isInNet(dnsResolve(host), "192.168.0.0", "255.255.0.0") ||
        isInNet(dnsResolve(host), "127.0.0.0", "255.255.255.0"))){
			return "DIRECT"
		}
           

剛才說過了,host是自url中分離出來的主機網址,首先使用dns解析為IP位址,然後判斷是否屬于給定的網段。如果是,則傳回直連,表示這個網段不通過代理來通路。

上面舉例的PAC完整檔案的例子,是我使用的PAC檔案,其中使用了相反的邏輯。是某幾個網站則使用相應代理,否則全部直連。是以沒有使用isInNet和dnsResolve函數。但很多人習慣的時候還是會用到。

使用這種方式後,在iPhone可以愉快的上網,當然仍然有些情況沒辦法解決。比如facebook app,并沒有使用http/https類的協定,而是直接使用tcp/ssl的連結擷取資料。這種情況下設定代理和使用PAC都是無效的,目前沒有什麼好辦法。着急的時候可以使用手機浏覽器通路https://m.facebook.com來對付對付,體驗方面,肯定差多了。

參考資料:

https://zhiwei.li/text/2015/08/16/用代理自動配置檔案pac給iphone和ipad裝置添加socks代理/