非常教程

HTTP参考手册

指南 | Guides

Proxy servers and tunneling: Proxy Auto-Configuration (PAC) file

一个代理服务器自动配置(PAC)文件是一个JavaScript函数,确定网络浏览器的请求(HTTP,HTTPS和FTP)是否直接去目的地或转发到Web代理服务器。包含在PAC文件中的JavaScript函数定义了这个函数:

function FindProxyForURL(url, host){
    // ...
}        

ret = FindProxyForURL(url, host);

句法

function FindProxyForURL(url, host)

参数

url正在访问的URL。https://URL 的路径和查询组件被剥离。在Chrome中,您可以通过设置PacHttpsUrlStrippingEnabled为禁用此功能false,在Firefox中,首选项是network.proxy.autoconfig_url.include_path.host从URL中提取的主机名。这只是为了方便; 它与之间://和第一个:/之后是相同的字符串。端口号不包含在此参数中。它可以在必要时从URL中提取。

Description

返回描述配置的字符串。该字符串的格式在下面的返回值格式中定义。

返回值格式

  • JavaScript函数返回单个字符串
  • 如果字符串为空,则不应使用代理
  • 该字符串可以包含任意数量的以分号分隔的构建块:

DIRECTConnections应直接进行,而不使用任何代理PROXY _host:port_应使用指定的代理SOCKS _host:port_应使用指定的SOCKS服务器

最近的Firefox支持版本也是这样:

HTTP_host:port_应使用指定的代理HTTP_host:port_应使用指定的HTTPS代理SOCKS4_host:port_SOCKS5_host:port_应使用指定的SOCKS服务器(具有指定的SOCK版本)

如果有多个以分号分隔的设置,则将使用最左侧的设置,直到Firefox无法建立与代理的连接。在那种情况下,下一个值将被使用,等等。

30分钟后,浏览器将自动重试以前无响应的代理。额外的尝试将在一小时后开始,总是在两次尝试之间增加30分钟。

如果所有代理都关闭,并且没有指定DIRECT选项,浏览器将询问是否应暂时忽略代理,并尝试直接连接。20分钟后,浏览器会询问代理是否应该重试,再过40分钟后再询问。查询将继续,总是在查询之间经过的时间增加20分钟。

例子

PROXY w3proxy.netscape.com:8080; PROXY mozilla.netscape.com:8081一级代理是w3proxy:8080; 如果发生故障,开始使用mozilla:8081,直到主代理再次出现。PROXY w3proxy.netscape.com:8080; PROXY mozilla.netscape.com:8081; DIRECTSame如上所述,但是如果两个代理都关闭了,自动开始直接连接。(在上面的第一个例子中,Netscape会询问用户确认是否有直接连接;在这种情况下,没有用户干预。)PROXY w3proxy.netscape.com:8080; SOCKS socks:如果主代理服务器关闭,则使用SOCKS。

自动配置文件应该保存到一个带有.pac文件扩展名的文件中:

proxy.pac

而MIME类型设置为:

application/x-ns-proxy-autoconfig

接下来,您应该配置服务器将.pac文件扩展名映射到MIME类型。

笔记:

  • JavaScript函数应该总是保存到文件中,而不是嵌入到HTML中。
  • 本文末尾的示例已完成。没有其他语法需要将其保存到文件中并使用它。(当然,必须编辑JavaScript以反映您的网站的域名和/或子网。)

预定义的功能和环境

这些函数可用于构建PAC文件:

  • Hostname based conditions
    • isPlainHostName()(about:blank#isPlainHostName(%29)
    • dnsDomainIs()(about:blank#dnsDomainIs(host,%20domain%29)
    • localHostOrDomainIs()(about:blank#localHostOrDomainIs(host,%20hostdom%29)
    • isResolvable()(about:blank#isResolvable(host%29)
    • isInNet()(about:blank#isInNet(host,%20pattern,%20mask%29)
  • Related utility functions
    • dnsResolve()(about:blank#dnsResolve(host%29)
    • convert_addr()(about:blank#convert_addr(%29)
    • myIpAddress()(about:blank#myIpAddress(%29)
    • dnsDomainLevels()(about:blank#dnsDomainLevels(host%29)
  • URL/hostname based conditions
    • shExpMatch()(about:blank#shExpMatch(str,%20shexp%29)
  • Time based conditions
    • weekdayRange()(about:blank#weekdayRange(wd1,%20wd2,%20gmt%29)
    • dateRange()(about:blank#dateRange(%29)
    • timeRange()(about:blank#timeRange(%29)
  • There is one associative array already defined (because a JavaScript currently cannot define them on its own):
    • ProxyConfig.bindings

注意: pactester(pacparser包的一部分)用于测试以下语法示例。

  • The PAC file is named proxy.pac
  • Command line: pactester -p ~/pacparser-master/tests/proxy.pac -u http://www.mozilla.org
    • This command passes the host parameter www.mozilla.org and the url parameter http://www.mozilla.org.

isPlainHostName()

句法

isPlainHostName(host)

参数

主机URL中的主机名(不包括端口号)。

描述

当且仅当主机名中没有域名(无点)时才为真。

例子

function FindProxyForURL(url, host) {
  if (!isPlainHostName(host))
    return host;
}

//returns "www.mozilla.org"
function FindProxyForURL(url, host) {
  if (isPlainHostName("www"))
    return "isPlainHostName is true";
  return "isPlainHostName is false";
}

//returns "isPlainHostName is true"

dnsDomainIs()

句法

dnsDomainIs(host, domain)

参数

主机是来自URL的主机名。域用来测试主机名。

描述

当且仅当主机名的域匹配时返回true。

例子

function FindProxyForURL(url, host) {
  if (dnsDomainIs("www.mozilla.org", ".mozilla.org"))
    return "dnsDomainIs is true";
  return "dnsDomainIs is false";
}

//returns "dnsDomainIs is true"
function FindProxyForURL(url, host) {
  if (dnsDomainIs("www", ".mozilla.org"))
    return "dnsDomainIs is true";
  return "dnsDomainIs is false";
}

//returns "dnsDomainIs is false"

localHostOrDomainIs()

句法

localHostOrDomainIs(host, hostdom)

参数

hosthost从URL.hostdomFully限定的主机名中匹配的主机名。

描述

如果主机名与指定的主机名完全匹配,或者主机名中没有域名部分,但未匹配的主机名匹配,则为true。

例子

function FindProxyForURL(url, host) {
  if (localHostOrDomainIs("www.mozilla.org", "www.mozilla.org"))
    return "localHostOrDomainIs is true (exact match)";
  return "localHostOrDomainIs is false";
}

//returns "localHostOrDomainIs is true (exact match)"
function FindProxyForURL(url, host) {
  if (localHostOrDomainIs("www", "www.mozilla.org"))
    return "localHostOrDomainIs is true (hostname match, domain not specified))";
  return "localHostOrDomainIs is false";
}

//returns "localHostOrDomainIs is true (hostname match, domain not specified))"
function FindProxyForURL(url, host) {
  if (localHostOrDomainIs("www.google.com", "www.mozilla.org"))
    return "localHostOrDomainIs is true";
  return "localHostOrDomainIs is false (domain name mismatch)";
} 

// returns "localHostOrDomainIs is false (domain name mismatch)"
function FindProxyForURL(url, host) {
  if (localHostOrDomainIs("home.mozilla.org", "www.mozilla.org"))
    return "localHostOrDomainIs is true";
  return "localHostOrDomainIs is false (domain name mismatch)"; 
}

// returns "localHostOrDomainIs is false (hostname mismatch)"

isResolvable()

句法

isResolvable(host)

参数

hostis是URL中的主机名。

尝试解析主机名。成功返回true。

例子:

function FindProxyForURL(url, host) {
  if (isResolvable("www.mozilla.org"))
    return "isResolvable is true";
  return "isResolvable is false";
}

// returns "isResolvable is true"

isInNet()

句法

isInNet(host, pattern, mask)

参数

hosta DNS主机名或IP地址。如果一个主机名被传递,它将通过这个函数被解析为一个IP地址。在IP地址模式中用点分隔的格式.maskmask表示IP地址模式,通知应匹配IP地址的哪些部分。0表示忽略,255表示匹配。

当且仅当主机的IP地址与指定的IP地址模式匹配时才为真。

模式和模板规范的完成方式与SOCKS配置相同。

例子:

function FindProxyForURL(url, host) {
// put in the address returned by dnsResolve (see next example)
  if (isInNet(host, "63.245.213.24", "255.255.255.255"))
    return "isInNet is true";
  return "isInNet is false";
}

// returns "isInNet is true"

dnsResolve()

dnsResolve(host)

参数

hosthostname来解决。

将给定的DNS主机名解析为IP地址,并以点分隔格式将其作为字符串返回。

function FindProxyForURL(url, host) {
  return dnsResolve("www.mozilla.org");
} 

//returns the string "104.16.41.2"

convert_addr()

句法

convert_addr(ipaddr)

参数

ipaddrAny虚线地址,如IP地址或掩码。

将四个点分隔的字节连接成一个4字节的字并将其转换为十进制。

function FindProxyForURL(url, host) {
  return convert_addr("104.16.41.2");
} 

//returns the decimal number 1745889538

myIpAddress()

句法

myIpAddress()

参数

(none)

以点分隔的整数格式返回运行Firefox的计算机的服务器IP地址,作为字符串。

myIpAddress()返回与nslookup localhostLinux机器返回的服务器地址相同的IP地址。它不返回公共IP地址。

function FindProxyForURL(url, host) {
  return myIpAddress();
} 

//returns the string "127.0.1.1" if you were running Firefox on that localhost

dnsDomainLevels()

句法

dnsDomainLevels(host)

参数

hostis是URL中的主机名。

返回主机名中的DNS域级别(点数)的数量(整数)。

例子:

function FindProxyForURL(url, host) {
  return dnsDomainLevels("www");
}

//returns 0
function FindProxyForURL(url, host) {
  return dnsDomainLevels("mozilla.org");
}

//returns 1
function FindProxyForURL(url, host) {
  return dnsDomainLevels("www.mozilla.org");
}

//returns 2

shExpMatch()

句法

shExpMatch(str, shexp)

参数

stris要比较的任何字符串(例如,URL或主机名).shexp是一个shell表达式来比较。

如果字符串匹配指定的shell表达式,则返回true。

目前,这些模式是 shell表达式,而不是正则表达式。

例子

function FindProxyForURL(url, host) {
  return shExpMatch("http://home.netscape.com/people/ari/index.html", "*/ari/*");
}

//returns true
function FindProxyForURL(url, host) {
  return shExpMatch("http://home.netscape.com/people/montulli/index.html", "*/ari/*");
}

//returns false

weekdayRange()

句法

weekdayRange(wd1, wd2, gmt)

注意:(在Firefox 49之前)如果您希望函数将这些参数作为范围进行评估,则wd1必须小于wd2。看到下面的警告。

参数

有序周日字符串的wd1和wd2One:

"SUN"|"MON"|"TUE"|"WED"|"THU"|"FRI"|"SAT"

gmtI字符串“GMT”或被忽略。

只有第一个参数是强制性的。第二,第三或两者都可能被排除在外。

如果仅存在一个参数,则该函数在参数代表的星期几返回true值。如果将字符串“GMT”指定为第二个参数,则时间取为GMT。否则,他们被认为是在当地的时区。

如果wd1wd1都已定义,则当前工作日在两个有序工作日之间时,条件为真。界限是包容性的,但界限是有序的。如果指定了“GMT”参数,则时间取为GMT。否则,使用本地时区。

日子的顺序很重要 ; 在Firefox 49之前,总是会评估为真。现在只会在当前日期为星期三或星期日的情况下评估为真。weekdayRange("SUN", "SAT")weekdayRange("WED", "SUN")

例子

function FindProxyForURL(url, host) {
  return weekdayRange("MON", "FRI");
}

//returns true Monday through Friday (local timezone)
function FindProxyForURL(url, host) {
  return weekdayRange("MON", "FRI", "GMT");
}

//returns true Monday through Friday (GMT timezone)
function FindProxyForURL(url, host) {
  return weekdayRange("SAT");
}

//returns true true on Saturdays local time
function FindProxyForURL(url, host) {
  return weekdayRange("SAT", "GMT");
}

//returns true on Saturdays GMT time
function FindProxyForURL(url, host) {
  return weekdayRange("FRI", "MON");
}

//returns true Friday and Monday only (note, order does matter!)

dateRange()

句法

dateRange(<day1>, <month1>, <year1>, <day2>, <month2>, <year2>, <gmt>)

注意:(在Firefox 49之前)如果您希望函数将这些参数评估为范围,则day1必须小于day2,month1必须小于month2,并且year1必须小于year2。看到下面的警告。

参数

day是1到31之间的月份的有序日期(作为整数)。

1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31

月是下面的有序月份字符串之一。

"JAN"|"FEB"|"MAR"|"APR"|"MAY"|"JUN"|"JUL"|"AUG"|"SEP"|"OCT"|"NOV"|"DEC"

年是订购的全年整数。例如,2016(不是 16).gmt是字符串“GMT”,它在GMT时区中进行时间比较,或者被忽略。如果没有指定,时间将被视为在当地时区。

如果只指定了一个值(来自每个类别:日,月,年),则该函数仅在符合该规范的日期才返回真值。如果同时指定了这两个值,则结果在这些时间之间为真,包括边界,但边界是有序的

日期,月份和年份的顺序很重要 ; 在Firefox 49之前,会一直评估为。如果当前月份是12月或1月,现在只会评估为真。dateRange("JAN", "DEC")truedateRange("DEC", "JAN")

例子

function FindProxyForURL(url, host) {
  return dateRange(1);
}

//returns true on the first day of each month, local timezone
function FindProxyForURL(url, host) {
  return dateRange(1, "GMT")
}

//returns true on the first day of each month, GMT timezone
function FindProxyForURL(url, host) {
  return dateRange(1, 15);
}

//returns true on the first half of each month
function FindProxyForURL(url, host) {
  return dateRange(24, "DEC");
}

//returns true on 24th of December each year
function FindProxyForURL(url, host) {
  return dateRange("JAN", "MAR");
}

//returns true on the first quarter of the year
function FindProxyForURL(url, host) {
  return dateRange(1, "JUN", 15, "AUG");
}

//returns true from June 1st until August 15th, each year (including June 1st and August 15th)
function FindProxyForURL(url, host) {
  return dateRange(1, "JUN", 1995, 15, "AUG", 1995);
}

//returns true from June 1st, 1995, until August 15th, same year
function FindProxyForURL(url, host) {
  return dateRange("OCT", 1995, "MAR", 1996);
}

//returns true from October 1995 until March 1996 (including the entire month of October 1995 and March 1996)
function FindProxyForURL(url, host) {
  return dateRange(1995);
}

//returns true during the entire year of 1995
function FindProxyForURL(url, host) {
  return dateRange(1995, 1997);
}

//returns true from beginning of year 1995 until the end of year 1997

timeRange()

句法

timeRange(<hour1>, <min1>, <sec1>, <hour2>, <min2>, <sec2>, <gmt>)

注意:(在Firefox 49之前)如果希望函数将这些参数评估为范围,则类别hour1,min1,sec1必须小于类别hour2,min2,sec2。看到下面的警告。

参数

hour是0到23之间的小时。(0是午夜,23是晚上11点。)minMinutes从0到59.secSeconds从0到59.gmt GMT或时区字符串“GMT”,或未指定,用于本地时区。

如果只指定了一个值(来自每个类别:小时,分钟,秒),则该函数仅在符合该规范的时候返回真值。如果同时指定了这两个值,则结果在这些时间之间为真,包括边界,但边界是有序的

小时,分钟,秒的顺序 ; 在Firefox 49之前,总是会评估为真。现在只会在当前时间为23:00或午夜时评估为真。timeRange(0, 23)timeRange(23, 0)

例子

function FindProxyForURL(url, host) {
  return timerange(12);
}

//returns true from noon to 1pm
function FindProxyForURL(url, host) {
  return timerange(12, 13);
}

//returns true from noon to 1pm
function FindProxyForURL(url, host) {
  return timerange(12, "GMT");
}

//true from noon to 1pm, in GMT timezone
function FindProxyForURL(url, host) {
  return timerange(9, 17);
}

//returns true from 9am to 5pm
function FindProxyForURL(url, host) {
  return timerange(8, 30, 17, 00);
}

//returns true from 8:30am to 5:00pm
function FindProxyForURL(url, host) {
  return timerange(0, 0, 0, 0, 0, 30);
}

//returns true between midnight and 30 seconds past midnight

例1

对本地主机以外的所有内容使用代理

注意:由于以下所有示例都非常具体,因此尚未经过测试。

所有未完全限定的主机或者本地域中的主机都将直接连接。其他一切都将通过w3proxy:8080。如果代理服务器关闭,连接将自动变为直接连接:

function FindProxyForURL(url, host) {
  if (isPlainHostName(host) || dnsDomainIs(host, ".mozilla.org")) {
    return "DIRECT";
  } else {
    return "PROXY w3proxy.mozilla.org:8080; DIRECT";
  }
}

注意:对于只有一个代理的情况,这是最简单和最有效的autoconfig文件。

例2

如上所述,但是使用代理服务器在防火墙之外

如果存在属于本地域但位于防火墙之外且只能通过代理服务器访问的主机(如主Web服务器),则可以使用以下localHostOrDomainIs()函数处理这些异常:

function FindProxyForURL(url, host) {
  if ((isPlainHostName(host) ||
      dnsDomainIs(host, ".mozilla.org")) &&
      !localHostOrDomainIs(host, "www.mozilla.org") &&
      !localHostOrDoaminIs(host, "merchant.mozilla.org")) {
        return "DIRECT";
  } else {
    return "PROXY w3proxy.mozilla.org:8080; DIRECT";
  }
}

上述示例将使用代理服务器,除mozilla.org域中的本地主机以外的所有其他服务器,但主机www.mozilla.org和merchant.mozilla.org将通过代理服务器的情况进一步例外。

请注意以上效率的例外顺序:localHostOrDomainIs()函数仅针对本地域中的URL执行,而不是针对每个URL执行。注意在表达式之前的表达式的圆括号以实现上述有效行为。

例3

仅在无法解析主机时才使用代理

此示例适用于内部DNS服务器设置为只能解析内部主机名的环境,目标是仅为不可解析的主机使用代理:

function FindProxyForURL(url, host) {
  if (isResolvable(host))
    return "DIRECT";
  else
    return "PROXY proxy.mydomain.com:8080";
}

以上需要每次查询DNS; 它可以与其他规则进行智能分组,以便仅在其他规则不产生结果时才咨询DNS:

function FindProxyForURL(url, host) {
  if (isPlainHostName(host) ||
      dnsDomainIs(host, ".mydomain.com") ||
      isResolvable(host)) {
    return "DIRECT";
  } else {
    return "PROXY proxy.mydomain.com:8080";
  }
}

例4

基于子网的决定

在这个例子中,给定子网中的所有主机直接连接,其他连接通过代理连接:

function FindProxyForURL(url, host) {
  if (isInNet(host, "198.95.0.0", "255.255.0.0"))
    return "DIRECT";
  else
    return "PROXY proxy.mydomain.com:8080";
}

同样,通过在开始时添加冗余规则,可以最大限度地减少上述DNS服务器的使用:

function FindProxyForURL(url, host) {
  if (isPlainHostName(host) ||
      dnsDomainIs(host, ".mydomain.com") ||
      isInNet(host, "198.95.0.0", "255.255.0.0")) {
    return "DIRECT";
  } else {
    return "PROXY proxy.mydomain.com:8080";
  }
}

例5

基于URL模式的负载均衡/路由

这个例子更复杂。有四(4)个代理服务器; 其中一个对所有其他人来说都是一个热门候补,所以如果其余三个中的任何一个倒下,第四个将会接管。此外,剩余的三台代理服务器根据URL模式共享负载,这使得它们的缓存更加有效(三台服务器上只有一个文档副本 - 而不是每个副本上的副本)。负载分布如下:

Proxy

Purpose

#1

.com domain

#2

.edu domain

#3

all other domains

#4

hot stand-by

所有本地访问都希望是直接的。所有代理服务器都在端口8080上运行(它们不需要)。请注意字符串如何与JavaScript中的+运算符连接。

function FindProxyForURL(url, host) {
  if (isPlainHostName(host) || dnsDomainIs(host, ".mydomain.com"))
      return "DIRECT";
  else if (shExpMatch(host, "*.com"))
      return "PROXY proxy1.mydomain.com:8080; " +
             "PROXY proxy4.mydomain.com:8080";
  else if (shExpMatch(host, "*.edu"))
      return "PROXY proxy2.mydomain.com:8080; " +
             "PROXY proxy4.mydomain.com:8080";
  else
      return "PROXY proxy3.mydomain.com:8080; " +
             "PROXY proxy4.mydomain.com:8080";
}

例6

为特定协议设置代理

大多数标准的JavaScript功能可用于FindProxyForURL()函数。例如,要根据协议设置不同的代理,可以使用substring()函数:

function FindProxyForURL(url, host) {
  if (url.substring(0, 5) == "http:") {
    return "PROXY http-proxy.mydomain.com:8080";
  }
  else if (url.substring(0, 4) == "ftp:") {
    return "PROXY ftp-proxy.mydomain.com:8080";
  }
  else if (url.substring(0, 7) == "gopher:") {
    return "PROXY gopher-proxy.mydomain.com:8080";
  }
  else if (url.substring(0, 6) == "https:" ||
           url.substring(0, 6) == "snews:") {
    return "PROXY security-proxy.mydomain.com:8080";
  } else {
    return "DIRECT";
  }
}

注意:使用前面介绍的shExpMatch()函数可以完成相同的操作。

例如:

// ...
if (shExpMatch(url, "http:*")) {
  return "PROXY http-proxy.mydomain.com:8080;
}
// ...

自动配置文件可以由CGI脚本输出。例如,当根据客户端IP地址(CGI中的REMOTE_ADDR环境变量)使自动配置文件的行为不同时,这很有用。

使用isInNet()isResolvable()dnsResolve()功能应该仔细考虑,因为它们需要被咨询的DNS服务器。所有其他与自动配置相关的功能都是单纯的字符串匹配功能,不需要使用DNS服务器。如果使用代理服务器,代理服务器将执行其DNS查找,这将使DNS服务器的影响加倍。大多数情况下,这些功能对于达到预期效果并不是必需的。

在MDN上编辑此页(https://developer.mozilla.org/en-US/docs/Web/HTTP/Proxy servers_and_tunneling / Proxy_Auto-Configuration(PAC%29_file $ edit)