From 310fd066e91f454b990372ffa30e803cc8120975 Mon Sep 17 00:00:00 2001 From: Florian Merz Date: Thu, 11 Feb 2021 12:56:40 +0100 Subject: unslug zh-cn: move --- .../zh-cn/web/http/access_control_cors/index.html | 510 -------------- .../web/http/basics_of_http/data_uris/index.html | 116 ++++ files/zh-cn/web/http/caching/index.html | 163 +++++ files/zh-cn/web/http/caching_faq/index.html | 163 ----- .../index.html" | 248 ------- .../list_of_default_accept_values/index.html | 248 +++++++ .../errors/corsmissingallowcredentials/index.html | 32 + .../index.html" | 32 - files/zh-cn/web/http/cors/index.html | 510 ++++++++++++++ files/zh-cn/web/http/data_uris/index.html | 116 ---- files/zh-cn/web/http/feature_policy/index.html | 153 +++++ .../feature_policy/using_feature_policy/index.html | 140 ++++ .../headers/strict-transport-security/index.html | 121 ++++ .../http/headers/x-dns-prefetch-control/index.html | 97 +++ .../web/http/headers/x-frame-options/index.html | 161 +++++ .../zh-cn/web/http/http_response_codes/index.html | 13 - .../http/http_strict_transport_security/index.html | 121 ---- .../proxy_auto-configuration_(pac)_file/index.html | 729 --------------------- .../proxy_auto-configuration_pac_file/index.html | 729 +++++++++++++++++++++ .../web/http/server-side_access_control/index.html | 249 ------- files/zh-cn/web/http/x-frame-options/index.html | 161 ----- .../index.html" | 153 ----- .../using_feature_policy/index.html" | 140 ---- .../index.html" | 544 --------------- 24 files changed, 2470 insertions(+), 3179 deletions(-) delete mode 100644 files/zh-cn/web/http/access_control_cors/index.html create mode 100644 files/zh-cn/web/http/basics_of_http/data_uris/index.html create mode 100644 files/zh-cn/web/http/caching/index.html delete mode 100644 files/zh-cn/web/http/caching_faq/index.html delete mode 100644 "files/zh-cn/web/http/content_negotiation/accept_\351\273\230\350\256\244\345\200\274/index.html" create mode 100644 files/zh-cn/web/http/content_negotiation/list_of_default_accept_values/index.html create mode 100644 files/zh-cn/web/http/cors/errors/corsmissingallowcredentials/index.html delete mode 100644 "files/zh-cn/web/http/cors/errors/cors\351\224\231\350\257\257\345\205\201\350\256\270\345\207\255\350\257\201/index.html" create mode 100644 files/zh-cn/web/http/cors/index.html delete mode 100644 files/zh-cn/web/http/data_uris/index.html create mode 100644 files/zh-cn/web/http/feature_policy/index.html create mode 100644 files/zh-cn/web/http/feature_policy/using_feature_policy/index.html create mode 100644 files/zh-cn/web/http/headers/strict-transport-security/index.html create mode 100644 files/zh-cn/web/http/headers/x-dns-prefetch-control/index.html create mode 100644 files/zh-cn/web/http/headers/x-frame-options/index.html delete mode 100644 files/zh-cn/web/http/http_response_codes/index.html delete mode 100644 files/zh-cn/web/http/http_strict_transport_security/index.html delete mode 100644 files/zh-cn/web/http/proxy_servers_and_tunneling/proxy_auto-configuration_(pac)_file/index.html create mode 100644 files/zh-cn/web/http/proxy_servers_and_tunneling/proxy_auto-configuration_pac_file/index.html delete mode 100644 files/zh-cn/web/http/server-side_access_control/index.html delete mode 100644 files/zh-cn/web/http/x-frame-options/index.html delete mode 100644 "files/zh-cn/web/http/\347\255\226\347\225\245\347\211\271\345\276\201/index.html" delete mode 100644 "files/zh-cn/web/http/\347\255\226\347\225\245\347\211\271\345\276\201/using_feature_policy/index.html" delete mode 100644 "files/zh-cn/web/http/\350\267\250\345\237\237\350\265\204\346\272\220\345\205\261\344\272\253(cors)_/index.html" (limited to 'files/zh-cn/web/http') diff --git a/files/zh-cn/web/http/access_control_cors/index.html b/files/zh-cn/web/http/access_control_cors/index.html deleted file mode 100644 index c7acc1344d..0000000000 --- a/files/zh-cn/web/http/access_control_cors/index.html +++ /dev/null @@ -1,510 +0,0 @@ ---- -title: 跨源资源共享(CORS) -slug: Web/HTTP/Access_control_CORS -tags: - - AJAX - - CORS - - Cross-Origin Resource Sharing - - Fetch - - Fetch API - - HTTP - - HTTP Access Controls - - Same-origin policy - - Security - - XMLHttpRequest - - 'l10n:priority' -translation_of: Web/HTTP/CORS ---- -
{{HTTPSidebar}}
- -

跨源资源共享 ({{Glossary("CORS")}}) (或通俗地译为跨域资源共享)是一种基于{{Glossary("HTTP")}} 头的机制,该机制通过允许服务器标示除了它自己以外的其它{{glossary("origin")}}(域,协议和端口),这样浏览器可以访问加载这些资源。跨源资源共享还通过一种机制来检查服务器是否会允许要发送的真实请求,该机制通过浏览器发起一个到服务器托管的跨源资源的"预检"请求。在预检中,浏览器发送的头中标示有HTTP方法和真实请求中会用到的头。

- -

跨源HTTP请求的一个例子:运行在 http://domain-a.com 的JavaScript代码使用{{domxref("XMLHttpRequest")}}来发起一个到 https://domain-b.com/data.json 的请求。

- -

出于安全性,浏览器限制脚本内发起的跨源HTTP请求。 例如,XMLHttpRequest和Fetch API遵循同源策略。 这意味着使用这些API的Web应用程序只能从加载应用程序的同一个域请求HTTP资源,除非响应报文包含了正确CORS响应头。

- -

- -

跨源域资源共享( {{Glossary("CORS")}} )机制允许 Web 应用服务器进行跨源访问控制,从而使跨源数据传输得以安全进行。现代浏览器支持在 API 容器中(例如 {{domxref("XMLHttpRequest")}} 或 Fetch )使用 CORS,以降低跨源 HTTP 请求所带来的风险。

- -

谁应该读这篇文章?

- -

说实话,每个人。

- -

更具体地来讲,这篇文章适用于网站管理员、后端和前端开发者。现代浏览器处理跨源资源共享的客户端部分,包括HTTP头和相关策略的执行。但是这一新标准意味着服务器需要处理新的请求头和响应头。对于服务端的支持,开发者可以阅读补充材料 cross-origin sharing from a server perspective (with PHP code snippets)

- -

什么情况下需要 CORS ?

- -

这份 cross-origin sharing standard 允许在下列场景中使用跨站点 HTTP 请求:

- - - -

本文概述了跨源资源共享机制及其所涉及的 HTTP 头。

- -

功能概述

- -

跨源资源共享标准新增了一组 HTTP 首部字段,允许服务器声明哪些源站通过浏览器有权限访问哪些资源。另外,规范要求,对那些可能对服务器数据产生副作用的 HTTP 请求方法(特别是 {{HTTPMethod("GET")}} 以外的 HTTP 请求,或者搭配某些 MIME 类型的 {{HTTPMethod("POST")}} 请求),浏览器必须首先使用 {{HTTPMethod("OPTIONS")}} 方法发起一个预检请求(preflight request),从而获知服务端是否允许该跨源请求。服务器确认允许之后,才发起实际的 HTTP 请求。在预检请求的返回中,服务器端也可以通知客户端,是否需要携带身份凭证(包括 Cookies 和 HTTP 认证相关数据)。

- -

CORS请求失败会产生错误,但是为了安全,在JavaScript代码层面是无法获知到底具体是哪里出了问题。你只能查看浏览器的控制台以得知具体是哪里出现了错误。

- -

接下来的内容将讨论相关场景,并剖析该机制所涉及的 HTTP 首部字段。

- -

若干访问控制场景

- -

这里,我们使用三个场景来解释跨源资源共享机制的工作原理。这些例子都使用 {{domxref("XMLHttpRequest")}} 对象。

- -

本文中的 JavaScript 代码片段都可以从 http://arunranga.com/examples/access-control/ 获得。另外,使用支持跨源  {{domxref("XMLHttpRequest")}} 的浏览器访问该地址,可以看到代码的实际运行结果。

- -

关于服务端对跨源资源共享的支持的讨论,请参见这篇文章: Server-Side_Access_Control (CORS)

- -

简单请求

- -

某些请求不会触发 CORS 预检请求。本文称这样的请求为“简单请求”,请注意,该术语并不属于 {{SpecName('Fetch')}} (其中定义了 CORS)规范。若请求满足所有下述条件,则该请求可视为“简单请求”:

- - - -
注意: 这些跨站点请求与浏览器发出的其他跨站点请求并无二致。如果服务器未返回正确的响应首部,则请求方不会收到任何数据。因此,那些不允许跨站点请求的网站无需为这一新的 HTTP 访问控制特性担心。
- -
注意: WebKit Nightly 和 Safari Technology Preview 为{{HTTPHeader("Accept")}}, {{HTTPHeader("Accept-Language")}}, 和 {{HTTPHeader("Content-Language")}} 首部字段的值添加了额外的限制。如果这些首部字段的值是“非标准”的,WebKit/Safari 就不会将这些请求视为“简单请求”。WebKit/Safari 并没有在文档中列出哪些值是“非标准”的,不过我们可以在这里找到相关讨论:Require preflight for non-standard CORS-safelisted request headers Accept, Accept-Language, and Content-Language, Allow commas in Accept, Accept-Language, and Content-Language request headers for simple CORS, and Switch to a blacklist model for restricted Accept headers in simple CORS requests。其它浏览器并不支持这些额外的限制,因为它们不属于规范的一部分。
- -

比如说,假如站点 http://foo.example 的网页应用想要访问 http://bar.other 的资源。http://foo.example 的网页中可能包含类似于下面的 JavaScript 代码:

- -
var invocation = new XMLHttpRequest();
-var url = 'http://bar.other/resources/public-data/';
-
-function callOtherDomain() {
-  if(invocation) {
-    invocation.open('GET', url, true);
-    invocation.onreadystatechange = handler;
-    invocation.send();
-  }
-}
-
- -

客户端和服务器之间使用 CORS 首部字段来处理权限:

- -

- -

分别检视请求报文和响应报文:

- -
GET /resources/public-data/ HTTP/1.1
-Host: bar.other
-User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre
-Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
-Accept-Language: en-us,en;q=0.5
-Accept-Encoding: gzip,deflate
-Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
-Connection: keep-alive
-Referer: http://foo.example/examples/access-control/simpleXSInvocation.html
-Origin: http://foo.example
-
-
-HTTP/1.1 200 OK
-Date: Mon, 01 Dec 2008 00:23:53 GMT
-Server: Apache/2.0.61
-Access-Control-Allow-Origin: *
-Keep-Alive: timeout=2, max=100
-Connection: Keep-Alive
-Transfer-Encoding: chunked
-Content-Type: application/xml
-
-[XML Data]
-
- -

第 1~10 行是请求首部。第10行 的请求首部字段 {{HTTPHeader("Origin")}} 表明该请求来源于 http://foo.example

- -

第 13~22 行是来自于 http://bar.other 的服务端响应。响应中携带了响应首部字段 {{HTTPHeader("Access-Control-Allow-Origin")}}(第 16 行)。使用 {{HTTPHeader("Origin")}} 和 {{HTTPHeader("Access-Control-Allow-Origin")}} 就能完成最简单的访问控制。本例中,服务端返回的 Access-Control-Allow-Origin: * 表明,该资源可以被任意外域访问。如果服务端仅允许来自 http://foo.example 的访问,该首部字段的内容如下:

- -

Access-Control-Allow-Origin: http://foo.example

- -

现在,除了 http://foo.example,其它外域均不能访问该资源(该策略由请求首部中的 ORIGIN 字段定义,见第10行)。Access-Control-Allow-Origin 应当为 * 或者包含由 Origin 首部字段所指明的域名。

- -

预检请求

- -

与前述简单请求不同,“需预检的请求”要求必须首先使用 {{HTTPMethod("OPTIONS")}}   方法发起一个预检请求到服务器,以获知服务器是否允许该实际请求。"预检请求“的使用,可以避免跨域请求对服务器的用户数据产生未预期的影响。

- -

如下是一个需要执行预检请求的 HTTP 请求:

- -
var invocation = new XMLHttpRequest();
-var url = 'http://bar.other/resources/post-here/';
-var body = '<?xml version="1.0"?><person><name>Arun</name></person>';
-
-function callOtherDomain(){
-  if(invocation)
-    {
-      invocation.open('POST', url, true);
-      invocation.setRequestHeader('X-PINGOTHER', 'pingpong');
-      invocation.setRequestHeader('Content-Type', 'application/xml');
-      invocation.onreadystatechange = handler;
-      invocation.send(body);
-    }
-}
-
-......
-
- -

上面的代码使用 POST 请求发送一个 XML 文档,该请求包含了一个自定义的请求首部字段(X-PINGOTHER: pingpong)。另外,该请求的 Content-Type 为 application/xml。因此,该请求需要首先发起“预检请求”。

- -

- -
OPTIONS /resources/post-here/ HTTP/1.1
-Host: bar.other
-User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre
-Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
-Accept-Language: en-us,en;q=0.5
-Accept-Encoding: gzip,deflate
-Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
-Connection: keep-alive
-Origin: http://foo.example
-Access-Control-Request-Method: POST
-Access-Control-Request-Headers: X-PINGOTHER, Content-Type
-
-
-HTTP/1.1 200 OK
-Date: Mon, 01 Dec 2008 01:15:39 GMT
-Server: Apache/2.0.61 (Unix)
-Access-Control-Allow-Origin: http://foo.example
-Access-Control-Allow-Methods: POST, GET, OPTIONS
-Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
-Access-Control-Max-Age: 86400
-Vary: Accept-Encoding, Origin
-Content-Encoding: gzip
-Content-Length: 0
-Keep-Alive: timeout=2, max=100
-Connection: Keep-Alive
-Content-Type: text/plain
- -

预检请求完成之后,发送实际请求:

- -
POST /resources/post-here/ HTTP/1.1
-Host: bar.other
-User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre
-Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
-Accept-Language: en-us,en;q=0.5
-Accept-Encoding: gzip,deflate
-Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
-Connection: keep-alive
-X-PINGOTHER: pingpong
-Content-Type: text/xml; charset=UTF-8
-Referer: http://foo.example/examples/preflightInvocation.html
-Content-Length: 55
-Origin: http://foo.example
-Pragma: no-cache
-Cache-Control: no-cache
-
-<?xml version="1.0"?><person><name>Arun</name></person>
-
-
-HTTP/1.1 200 OK
-Date: Mon, 01 Dec 2008 01:15:40 GMT
-Server: Apache/2.0.61 (Unix)
-Access-Control-Allow-Origin: http://foo.example
-Vary: Accept-Encoding, Origin
-Content-Encoding: gzip
-Content-Length: 235
-Keep-Alive: timeout=2, max=99
-Connection: Keep-Alive
-Content-Type: text/plain
-
-[Some GZIP'd payload]
- -

浏览器检测到,从 JavaScript 中发起的请求需要被预检。从上面的报文中,我们看到,第 1~12 行发送了一个使用 OPTIONS 方法的“预检请求”。 OPTIONS 是 HTTP/1.1 协议中定义的方法,用以从服务器获取更多信息。该方法不会对服务器资源产生影响。 预检请求中同时携带了下面两个首部字段:

- -
Access-Control-Request-Method: POST
-Access-Control-Request-Headers: X-PINGOTHER, Content-Type
- -

首部字段 {{HTTPHeader("Access-Control-Request-Method")}} 告知服务器,实际请求将使用 POST 方法。首部字段 {{HTTPHeader("Access-Control-Request-Headers")}} 告知服务器,实际请求将携带两个自定义请求首部字段:X-PINGOTHERContent-Type。服务器据此决定,该实际请求是否被允许。

- -

第14~26 行为预检请求的响应,表明服务器将接受后续的实际请求。重点看第 17~20 行:

- -
Access-Control-Allow-Origin: http://foo.example
-Access-Control-Allow-Methods: POST, GET, OPTIONS
-Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
-Access-Control-Max-Age: 86400
- -

首部字段 Access-Control-Allow-Methods 表明服务器允许客户端使用 POST, GET OPTIONS 方法发起请求。该字段与 HTTP/1.1 Allow: response header 类似,但仅限于在需要访问控制的场景中使用。

- -

首部字段 Access-Control-Allow-Headers 表明服务器允许请求中携带字段 X-PINGOTHER Content-Type Access-Control-Allow-Methods 一样,Access-Control-Allow-Headers 的值为逗号分割的列表。

- -

最后,首部字段 Access-Control-Max-Age 表明该响应的有效时间为 86400 秒,也就是 24 小时。在有效时间内,浏览器无须为同一请求再次发起预检请求。请注意,浏览器自身维护了一个最大有效时间,如果该首部字段的值超过了最大有效时间,将不会生效。

- -

预检请求与重定向

- -

大多数浏览器不支持针对于预检请求的重定向。如果一个预检请求发生了重定向,浏览器将报告错误:

- -
-

The request was redirected to 'https://example.com/foo', which is disallowed for cross-origin requests that require preflight

-
- -
-

Request requires preflight, which is disallowed to follow cross-origin redirect

-
- -

CORS 最初要求该行为,不过在后续的修订中废弃了这一要求

- -

在浏览器的实现跟上规范之前,有两种方式规避上述报错行为:

- - - -

如果上面两种方式难以做到,我们仍有其他办法:

- - - -

不过,如果请求是由于存在 Authorization 字段而引发了预检请求,则这一方法将无法使用。这种情况只能由服务端进行更改。

- -

附带身份凭证的请求

- -

{{domxref("XMLHttpRequest")}} 或 Fetch 与 CORS 的一个有趣的特性是,可以基于  HTTP cookies 和 HTTP 认证信息发送身份凭证。一般而言,对于跨源 {{domxref("XMLHttpRequest")}} 或 Fetch 请求,浏览器不会发送身份凭证信息。如果要发送凭证信息,需要设置 XMLHttpRequest 的某个特殊标志位。

- -

本例中,http://foo.example 的某脚本向 http://bar.other 发起一个GET 请求,并设置 Cookies:

- -
var invocation = new XMLHttpRequest();
-var url = 'http://bar.other/resources/credentialed-content/';
-
-function callOtherDomain(){
-  if(invocation) {
-    invocation.open('GET', url, true);
-    invocation.withCredentials = true;
-    invocation.onreadystatechange = handler;
-    invocation.send();
-  }
-}
- -

第 7 行将 XMLHttpRequest 的 withCredentials 标志设置为 true,从而向服务器发送 Cookies。因为这是一个简单 GET 请求,所以浏览器不会对其发起“预检请求”。但是,如果服务器端的响应中未携带 Access-Control-Allow-Credentials: true ,浏览器将不会把响应内容返回给请求的发送者。

- -

- -

客户端与服务器端交互示例如下:

- -
GET /resources/access-control-with-credentials/ HTTP/1.1
-Host: bar.other
-User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre
-Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
-Accept-Language: en-us,en;q=0.5
-Accept-Encoding: gzip,deflate
-Connection: keep-alive
-Referer: http://foo.example/examples/credential.html
-Origin: http://foo.example
-Cookie: pageAccess=2
-
-
-HTTP/1.1 200 OK
-Date: Mon, 01 Dec 2008 01:34:52 GMT
-Server: Apache/2
-Access-Control-Allow-Origin: http://foo.example
-Access-Control-Allow-Credentials: true
-Cache-Control: no-cache
-Pragma: no-cache
-Set-Cookie: pageAccess=3; expires=Wed, 31-Dec-2008 01:34:53 GMT
-Vary: Accept-Encoding, Origin
-Content-Encoding: gzip
-Content-Length: 106
-Keep-Alive: timeout=2, max=100
-Connection: Keep-Alive
-Content-Type: text/plain
-
-
-[text/plain payload]
- -

即使第 10 行指定了 Cookie 的相关信息,但是,如果 bar.other 的响应中缺失 {{HTTPHeader("Access-Control-Allow-Credentials")}}: true(第 17 行),则响应内容不会返回给请求的发起者。

- -

附带身份凭证的请求与通配符

- -

对于附带身份凭证的请求,服务器不得设置 Access-Control-Allow-Origin 的值为“*”。

- -

这是因为请求的首部中携带了 Cookie 信息,如果 Access-Control-Allow-Origin 的值为“*”,请求将会失败。而将 Access-Control-Allow-Origin 的值设置为 http://foo.example,则请求将成功执行。

- -

另外,响应首部中也携带了 Set-Cookie 字段,尝试对 Cookie 进行修改。如果操作失败,将会抛出异常。

- -

第三方 cookies

- -

注意在 CORS 响应中设置的 cookies 适用一般性第三方 cookie 策略。在上面的例子中,页面是在 `foo.example` 加载,但是第 20 行的 cookie 是被 `bar.other` 发送的,如果用户设置其浏览器拒绝所有第三方 cookies,那么将不会被保存。

- -

HTTP 响应首部字段

- -

本节列出了规范所定义的响应首部字段。上一小节中,我们已经看到了这些首部字段在实际场景中是如何工作的。

- -

Access-Control-Allow-Origin

- -

响应首部中可以携带一个 {{HTTPHeader("Access-Control-Allow-Origin")}} 字段,其语法如下:

- -
Access-Control-Allow-Origin: <origin> | *
-
- -

其中,origin 参数的值指定了允许访问该资源的外域 URI。对于不需要携带身份凭证的请求,服务器可以指定该字段的值为通配符,表示允许来自所有域的请求。

- -

例如,下面的字段值将允许来自 http://mozilla.com 的请求:

- -
Access-Control-Allow-Origin: http://mozilla.com
- -

如果服务端指定了具体的域名而非“*”,那么响应首部中的 Vary 字段的值必须包含 Origin。这将告诉客户端:服务器对不同的源站返回不同的内容。

- -

Access-Control-Expose-Headers

- -

译者注:在跨源访问时,XMLHttpRequest对象的getResponseHeader()方法只能拿到一些最基本的响应头,Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma,如果要访问其他头,则需要服务器设置本响应头。

- -

{{HTTPHeader("Access-Control-Expose-Headers")}} 头让服务器把允许浏览器访问的头放入白名单,例如:

- -
Access-Control-Expose-Headers: X-My-Custom-Header, X-Another-Custom-Header
-
- -

这样浏览器就能够通过getResponseHeader访问X-My-Custom-Header和 X-Another-Custom-Header 响应头了。

- -

Access-Control-Max-Age

- -

{{HTTPHeader("Access-Control-Max-Age")}} 头指定了preflight请求的结果能够被缓存多久,请参考本文在前面提到的preflight例子。

- -
Access-Control-Max-Age: <delta-seconds>
-
- -

delta-seconds 参数表示preflight请求的结果在多少秒内有效。

- -

Access-Control-Allow-Credentials

- -

{{HTTPHeader("Access-Control-Allow-Credentials")}} 头指定了当浏览器的credentials设置为true时是否允许浏览器读取response的内容。当用在对preflight预检测请求的响应中时,它指定了实际的请求是否可以使用credentials。请注意:简单 GET 请求不会被预检;如果对此类请求的响应中不包含该字段,这个响应将被忽略掉,并且浏览器也不会将相应内容返回给网页。

- -
Access-Control-Allow-Credentials: true
-
- -

上文已经讨论了附带身份凭证的请求

- -

Access-Control-Allow-Methods

- -

{{HTTPHeader("Access-Control-Allow-Methods")}} 首部字段用于预检请求的响应。其指明了实际请求所允许使用的 HTTP 方法。

- -
Access-Control-Allow-Methods: <method>[, <method>]*
-
- -

相关示例见这里

- -

Access-Control-Allow-Headers

- -

{{HTTPHeader("Access-Control-Allow-Headers")}} 首部字段用于预检请求的响应。其指明了实际请求中允许携带的首部字段。

- -
Access-Control-Allow-Headers: <field-name>[, <field-name>]*
-
- -

HTTP 请求首部字段

- -

本节列出了可用于发起跨源请求的首部字段。请注意,这些首部字段无须手动设置。 当开发者使用 XMLHttpRequest 对象发起跨源请求时,它们已经被设置就绪。

- -

Origin

- -

{{HTTPHeader("Origin")}} 首部字段表明预检请求或实际请求的源站。

- -
Origin: <origin>
-
- -

origin 参数的值为源站 URI。它不包含任何路径信息,只是服务器名称。

- -
Note: 有时候将该字段的值设置为空字符串是有用的,例如,当源站是一个 data URL 时。
- -

注意,在所有访问控制请求(Access control request)中,{{HTTPHeader("Origin")}} 首部字段总是被发送。

- -

Access-Control-Request-Method

- -

{{HTTPHeader("Access-Control-Request-Method")}} 首部字段用于预检请求。其作用是,将实际请求所使用的 HTTP 方法告诉服务器。

- -
Access-Control-Request-Method: <method>
-
- -

相关示例见这里

- -

Access-Control-Request-Headers

- -

{{HTTPHeader("Access-Control-Request-Headers")}} 首部字段用于预检请求。其作用是,将实际请求所携带的首部字段告诉服务器。

- -
Access-Control-Request-Headers: <field-name>[, <field-name>]*
-
- -

相关示例见这里

- -

规范

- - - - - - - - - - - - - - - - - - - -
SpecificationStatusComment
{{SpecName('Fetch', '#cors-protocol', 'CORS')}}{{Spec2('Fetch')}}New definition; supplants CORS specification.
{{SpecName('CORS')}}{{Spec2('CORS')}}Initial definition.
- -

浏览器兼容性

- - - -

{{Compat("http.headers.Access-Control-Allow-Origin")}}

- -

- - - -

参见

- - - -

{{ languages( { "ja": "ja/HTTP_access_control" } ) }}

diff --git a/files/zh-cn/web/http/basics_of_http/data_uris/index.html b/files/zh-cn/web/http/basics_of_http/data_uris/index.html new file mode 100644 index 0000000000..5153482967 --- /dev/null +++ b/files/zh-cn/web/http/basics_of_http/data_uris/index.html @@ -0,0 +1,116 @@ +--- +title: Data URLs +slug: Web/HTTP/data_URIs +tags: + - Base64 + - HTTP + - URL + - 教程 + - 进阶 +translation_of: Web/HTTP/Basics_of_HTTP/Data_URIs +--- +
{{HTTPSidebar}}
+ +

Data URLs,即前缀为 data: 协议的URL,其允许内容创建者向文档中嵌入小文件。

+ +

语法

+ +

Data URLs 由四个部分组成:前缀(data:)、指示数据类型的MIME类型、如果非文本则为可选的base64标记、数据本身:

+ +
data:[<mediatype>][;base64],<data>
+
+ +

mediatype 是个 MIME 类型的字符串,例如 "image/jpeg" 表示 JPEG 图像文件。如果被省略,则默认值为 text/plain;charset=US-ASCII

+ +

如果数据是文本类型,你可以直接将文本嵌入 (根据文档类型,使用合适的实体字符或转义字符)。如果是二进制数据,你可以将数据进行base64编码之后再进行嵌入。

+ +

下面是一些示例:

+ +
+
data:,Hello%2C%20World!
+
简单的 text/plain 类型数据
+
data:text/plain;base64,SGVsbG8sIFdvcmxkIQ%3D%3D
+
上一条示例的 base64 编码版本
+
data:text/html,%3Ch1%3EHello%2C%20World!%3C%2Fh1%3E
+
一个HTML文档源代码 <h1>Hello, World</h1>
+
data:text/html,<script>alert('hi');</script>
+
一个会执行 JavaScript alert 的 HTML 文档。注意 script 标签必须封闭。
+
+ +

给数据作 base64 编码

+ +

在Linux或者Mac OS系统上,你可以使用 uuencode 命令行工具来简单实现编码:

+ +
uuencode -m infile remotename
+
+ +

infile 参数表示要作 base64编码的文件名称,remotename 参数表示输出的文件名称, 实际上并没有在 data 方案的URLs 中使用。

+ +

输出结果如下:

+ +
begin-base64 664 test
+YSBzbGlnaHRseSBsb25nZXIgdGVzdCBmb3IgdGV2ZXIK
+====
+
+ +

以上 Data URL 会使用位于首行之后的编码后的数据

+ +

在网页上使用 JavaScript

+ +

Web APIs 已经有对 base64 进行编码解码的方法: Base64 encoding and decoding.

+ +

常见问题

+ +

下文介绍一些在使用data URIs时遇到的常见问题:

+ +
+
语法
+
data URLs 的格式很简单,但很容易会忘记把逗号加在 "data" 协议名后面,在对数据进行 base64 编码时也很容易发生错误。
+
HTML代码格式化
+
一个 data URL 是一个文件中的文件,相对于文档来说这个文件可能就非常的长。因为 data URL 也是 URL,所以 data 会用空白符(换行符, 制表符, 空格)来对它进行格式化。但如果数据是经过 base64 编码的,就可能会遇到一些问题
+
长度限制
+
虽然 Firefox 支持无限长度的 data URLs,但是标准中并没有规定浏览器必须支持任意长度的 data URIs。比如,Opera 11浏览器限制 URLs 最长为 65535 个字符,这意味着 data URLs 最长为 65529 个字符(如果你使用纯文本 data:, 而不是指定一个 MIME 类型的话,那么 65529 字符长度是编码后的长度,而不是源文件)。
+
缺乏错误处理
+
MIME类型错误或者base64编码错误,都会造成data URIs无法被正常解析, 但不会有任何相关错误提示.
+
不支持查询字符串
+
+

一个data URI的数据字段是没有结束标记的,所以尝试在一个data URI后面添加查询字符串会导致,查询字符串也一并被当作数据字段.例如:

+ +
data:text/html,lots of text...<p><a name%3D"bottom">bottom</a>?arg=val
+
+ +

这个 data URL 代表的 HTML 源文件内容为:

+ +
lots of text...<p><a name="bottom">bottom</a>?arg=val
+
+
+
+ +

浏览器兼容性

+ +

{{compat("http.data-url")}}

+ +

Specifications

+ + + + + + + + + + + + +
SpecificationTitle
{{RFC("2397")}}The "data" URL scheme
+ +

相关链接

+ + diff --git a/files/zh-cn/web/http/caching/index.html b/files/zh-cn/web/http/caching/index.html new file mode 100644 index 0000000000..3bf85cb945 --- /dev/null +++ b/files/zh-cn/web/http/caching/index.html @@ -0,0 +1,163 @@ +--- +title: HTTP 缓存 +slug: Web/HTTP/Caching_FAQ +tags: + - Cache-Control + - ETag + - Expires + - HTTP + - HTTP Cache + - Last-Modified + - 协商缓存 + - 强缓存 + - 指南 + - 缓存 +translation_of: Web/HTTP/Caching +--- +
{{HTTPSidebar}}
+ +

通过复用以前获取的资源,可以显著提高网站和应用程序的性能。Web 缓存减少了等待时间和网络流量,因此减少了显示资源表示形式所需的时间。通过使用 HTTP缓存,变得更加响应性。

+ +

不同种类的缓存

+ +

缓存是一种保存资源副本并在下次请求时直接使用该副本的技术。当 web 缓存发现请求的资源已经被存储,它会拦截请求,返回该资源的拷贝,而不会去源服务器重新下载。这样带来的好处有:缓解服务器端压力,提升性能(获取资源的耗时更短了)。对于网站来说,缓存是达到高性能的重要组成部分。缓存需要合理配置,因为并不是所有资源都是永久不变的:重要的是对一个资源的缓存应截止到其下一次发生改变(即不能缓存过期的资源)。

+ +

缓存的种类有很多,其大致可归为两类:私有与共享缓存。共享缓存存储的响应能够被多个用户使用。私有缓存只能用于单独用户。本文将主要介绍浏览器与代理缓存,除此之外还有网关缓存、CDN、反向代理缓存和负载均衡器等部署在服务器上的缓存方式,为站点和 web 应用提供更好的稳定性、性能和扩展性。

+ +

What a cache provide, advantages/disadvantages of shared/private caches.

+ +

(私有)浏览器缓存

+ +

私有缓存只能用于单独用户。你可能已经见过浏览器设置中的“缓存”选项。浏览器缓存拥有用户通过 HTTP 下载的所有文档。这些缓存为浏览过的文档提供向后/向前导航,保存网页,查看源码等功能,可以避免再次向服务器发起多余的请求。它同样可以提供缓存内容的离线浏览。

+ +

(共享)代理缓存

+ +

共享缓存可以被多个用户使用。例如,ISP 或你所在的公司可能会架设一个 web 代理来作为本地网络基础的一部分提供给用户。这样热门的资源就会被重复使用,减少网络拥堵与延迟。

+ +

缓存操作的目标

+ +

虽然 HTTP 缓存不是必须的,但重用缓存的资源通常是必要的。然而常见的 HTTP 缓存只能存储 {{HTTPMethod("GET")}} 响应,对于其他类型的响应则无能为力。缓存的关键主要包括request method和目标URI(一般只有GET请求才会被缓存)。 普遍的缓存案例:

+ + + +

针对一些特定的请求,也可以通过关键字区分多个存储的不同响应以组成缓存的内容。具体参考下文关于 {{HTTPHeader("Vary")}} 的信息。

+ +

缓存控制

+ +

Cache-control

+ +

HTTP/1.1定义的 {{HTTPHeader("Cache-Control")}} 头用来区分对缓存机制的支持情况, 请求头和响应头都支持这个属性。通过它提供的不同的值来定义缓存策略。

+ +

没有缓存

+ +

缓存中不得存储任何关于客户端请求和服务端响应的内容。每次由客户端发起的请求都会下载完整的响应内容。

+ +
Cache-Control: no-store
+ +

缓存但重新验证

+ +

如下头部定义,此方式下,每次有请求发出时,缓存会将此请求发到服务器(译者注:该请求应该会带有与本地缓存相关的验证字段),服务器端会验证请求中所描述的缓存是否过期,若未过期(注:实际就是返回304),则缓存才使用本地缓存副本。

+ +
Cache-Control: no-cache
+ +

私有和公共缓存

+ +

"public" 指令表示该响应可以被任何中间人(译者注:比如中间代理、CDN等)缓存。若指定了"public",则一些通常不被中间人缓存的页面(译者注:因为默认是private)(比如 带有HTTP验证信息(帐号密码)的页面 或 某些特定状态码的页面),将会被其缓存。

+ +

而 "private" 则表示该响应是专用于某单个用户的,中间人不能缓存此响应,该响应只能应用于浏览器私有缓存中。

+ +
Cache-Control: private
+Cache-Control: public
+ +

过期

+ +

过期机制中,最重要的指令是 "max-age=<seconds>",表示资源能够被缓存(保持新鲜)的最大时间。相对Expires而言,max-age是距离请求发起的时间的秒数。针对应用中那些不会改变的文件,通常可以手动设置一定的时长以保证缓存有效,例如图片、css、js等静态资源。

+ +

详情看下文关于缓存有效性的内容。

+ +
Cache-Control: max-age=31536000
+ +

验证方式

+ +

当使用了 "must-revalidate" 指令,那就意味着缓存在考虑使用一个陈旧的资源时,必须先验证它的状态,已过期的缓存将不被使用。详情看下文关于缓存校验的内容。

+ +
Cache-Control: must-revalidate
+ +

Pragma 头

+ +

{{HTTPHeader("Pragma")}} 是HTTP/1.0标准中定义的一个header属性,请求中包含Pragma的效果跟在头信息中定义Cache-Control: no-cache相同,但是HTTP的响应头没有明确定义这个属性,所以它不能拿来完全替代HTTP/1.1中定义的Cache-control头。通常定义Pragma以向后兼容基于HTTP/1.0的客户端。

+ +

新鲜度

+ +

理论上来讲,当一个资源被缓存存储后,该资源应该可以被永久存储在缓存中。由于缓存只有有限的空间用于存储资源副本,所以缓存会定期地将一些副本删除,这个过程叫做缓存驱逐。另一方面,当服务器上面的资源进行了更新,那么缓存中的对应资源也应该被更新,由于HTTP是C/S模式的协议,服务器更新一个资源时,不可能直接通知客户端更新缓存,所以双方必须为该资源约定一个过期时间,在该过期时间之前,该资源(缓存副本)就是新鲜的,当过了过期时间后,该资源(缓存副本)则变为陈旧的驱逐算法用于将陈旧的资源(缓存副本)替换为新鲜的,注意,一个陈旧的资源(缓存副本)是不会直接被清除或忽略的,当客户端发起一个请求时,缓存检索到已有一个对应的陈旧资源(缓存副本),则缓存会先将此请求附加一个If-None-Match头,然后发给目标服务器,以此来检查该资源副本是否是依然还是算新鲜的,若服务器返回了 304 (Not Modified)(该响应不会有带有实体信息),则表示此资源副本是新鲜的,这样一来,可以节省一些带宽。若服务器通过 If-None-Match 或 If-Modified-Since判断后发现已过期,那么会带有该资源的实体内容返回。

+ +

下面是上述缓存处理过程的一个图示:

+ +

Show how a proxy cache acts when a doc is not cache, in the cache and fresh, in the cache and stale.

+ +

对于含有特定头信息的请求,会去计算缓存寿命。比如Cache-control: max-age=N的头,相应的缓存的寿命就是N。通常情况下,对于不含这个属性的请求则会去查看是否包含Expires属性,通过比较Expires的值和头里面Date属性的值来判断是否缓存还有效。如果max-age和expires属性都没有,找找头里的Last-Modified信息。如果有,缓存的寿命就等于头里面Date的值减去Last-Modified的值除以10(注:根据rfc2626其实也就是乘以10%)。

+ +

缓存失效时间计算公式如下:

+ +
expirationTime = responseTime + freshnessLifetime - currentAge
+ +

上式中,responseTime 表示浏览器接收到此响应的那个时间点。

+ +

改进资源

+ +

我们使用缓存的资源越多,网站的响应能力和性能就会越好。为了优化缓存,过期时间设置得尽量长是一种很好的策略。对于定期或者频繁更新的资源,这么做是比较稳妥的,但是对于那些长期不更新的资源会有点问题。这些固定的资源在一定时间内受益于这种长期保持的缓存策略,但一旦要更新就会很困难。特指网页上引入的一些js/css文件,当它们变动时需要尽快更新线上资源。

+ +

web开发者发明了一种被 Steve Souders 称之为 revving 的技术[1] 。不频繁更新的文件会使用特定的命名方式:在URL后面(通常是文件名后面)会加上版本号。加上版本号后的资源就被视作一个完全新的独立的资源,同时拥有一年甚至更长的缓存过期时长。但是这么做也存在一个弊端,所有引用这个资源的地方都需要更新链接。web开发者们通常会采用自动化构建工具在实际工作中完成这些琐碎的工作。当低频更新的资源(js/css)变动了,只用在高频变动的资源文件(html)里做入口的改动。

+ +

这种方法还有一个好处:同时更新两个缓存资源不会造成部分缓存先更新而引起新旧文件内容不一致。对于互相有依赖关系的css和js文件,避免这种不一致性是非常重要的。

+ +

+ +

加在加速文件后面的版本号不一定是一个正式的版本号字符串,如1.1.3这样或者其他固定自增的版本数。它可以是任何防止缓存碰撞的标记例如hash或者时间戳。

+ +

缓存验证

+ +

用户点击刷新按钮时会开始缓存验证。如果缓存的响应头信息里含有"Cache-control: must-revalidate”的定义,在浏览的过程中也会触发缓存验证。另外,在浏览器偏好设置里设置Advanced->Cache为强制验证缓存也能达到相同的效果。

+ +

当缓存的文档过期后,需要进行缓存验证或者重新获取资源。只有在服务器返回强校验器或者弱校验器时才会进行验证。

+ +

ETags

+ +

作为缓存的一种强校验器,{{HTTPHeader("ETag")}} 响应头是一个对用户代理(User Agent, 下面简称UA)不透明(译者注:UA 无需理解,只需要按规定使用即可)的值。对于像浏览器这样的HTTP UA,不知道ETag代表什么,不能预测它的值是多少。如果资源请求的响应头里含有ETag, 客户端可以在后续的请求的头中带上 {{HTTPHeader("If-None-Match")}} 头来验证缓存。

+ +

{{HTTPHeader("Last-Modified")}} 响应头可以作为一种弱校验器。说它弱是因为它只能精确到一秒。如果响应头里含有这个信息,客户端可以在后续的请求中带上 {{HTTPHeader("If-Modified-Since")}} 来验证缓存。

+ +

当向服务端发起缓存校验的请求时,服务端会返回 {{HTTPStatus(200)}} ok表示返回正常的结果或者 {{HTTPStatus(304)}} Not Modified(不返回body)表示浏览器可以使用本地缓存文件。304的响应头也可以同时更新缓存文档的过期时间。

+ +

Vary 响应

+ +

{{HTTPHeader("Vary")}} HTTP 响应头决定了对于后续的请求头,如何判断是请求一个新的资源还是使用缓存的文件。

+ +

当缓存服务器收到一个请求,只有当前的请求和原始(缓存)的请求头跟缓存的响应头里的Vary都匹配,才能使用缓存的响应。

+ +

The Vary header leads cache to use more HTTP headers as key for the cache.

+ +

使用vary头有利于内容服务的动态多样性。例如,使用Vary: User-Agent头,缓存服务器需要通过UA判断是否使用缓存的页面。如果需要区分移动端和桌面端的展示内容,利用这种方式就能避免在不同的终端展示错误的布局。另外,它可以帮助 Google 或者其他搜索引擎更好地发现页面的移动版本,并且告诉搜索引擎没有引入Cloaking

+ +
Vary: User-Agent
+ +

因为移动版和桌面的客户端的请求头中的User-Agent不同, 缓存服务器不会错误地把移动端的内容输出到桌面端到用户。

+ +

参考

+ + + +
+
+
diff --git a/files/zh-cn/web/http/caching_faq/index.html b/files/zh-cn/web/http/caching_faq/index.html deleted file mode 100644 index 3bf85cb945..0000000000 --- a/files/zh-cn/web/http/caching_faq/index.html +++ /dev/null @@ -1,163 +0,0 @@ ---- -title: HTTP 缓存 -slug: Web/HTTP/Caching_FAQ -tags: - - Cache-Control - - ETag - - Expires - - HTTP - - HTTP Cache - - Last-Modified - - 协商缓存 - - 强缓存 - - 指南 - - 缓存 -translation_of: Web/HTTP/Caching ---- -
{{HTTPSidebar}}
- -

通过复用以前获取的资源,可以显著提高网站和应用程序的性能。Web 缓存减少了等待时间和网络流量,因此减少了显示资源表示形式所需的时间。通过使用 HTTP缓存,变得更加响应性。

- -

不同种类的缓存

- -

缓存是一种保存资源副本并在下次请求时直接使用该副本的技术。当 web 缓存发现请求的资源已经被存储,它会拦截请求,返回该资源的拷贝,而不会去源服务器重新下载。这样带来的好处有:缓解服务器端压力,提升性能(获取资源的耗时更短了)。对于网站来说,缓存是达到高性能的重要组成部分。缓存需要合理配置,因为并不是所有资源都是永久不变的:重要的是对一个资源的缓存应截止到其下一次发生改变(即不能缓存过期的资源)。

- -

缓存的种类有很多,其大致可归为两类:私有与共享缓存。共享缓存存储的响应能够被多个用户使用。私有缓存只能用于单独用户。本文将主要介绍浏览器与代理缓存,除此之外还有网关缓存、CDN、反向代理缓存和负载均衡器等部署在服务器上的缓存方式,为站点和 web 应用提供更好的稳定性、性能和扩展性。

- -

What a cache provide, advantages/disadvantages of shared/private caches.

- -

(私有)浏览器缓存

- -

私有缓存只能用于单独用户。你可能已经见过浏览器设置中的“缓存”选项。浏览器缓存拥有用户通过 HTTP 下载的所有文档。这些缓存为浏览过的文档提供向后/向前导航,保存网页,查看源码等功能,可以避免再次向服务器发起多余的请求。它同样可以提供缓存内容的离线浏览。

- -

(共享)代理缓存

- -

共享缓存可以被多个用户使用。例如,ISP 或你所在的公司可能会架设一个 web 代理来作为本地网络基础的一部分提供给用户。这样热门的资源就会被重复使用,减少网络拥堵与延迟。

- -

缓存操作的目标

- -

虽然 HTTP 缓存不是必须的,但重用缓存的资源通常是必要的。然而常见的 HTTP 缓存只能存储 {{HTTPMethod("GET")}} 响应,对于其他类型的响应则无能为力。缓存的关键主要包括request method和目标URI(一般只有GET请求才会被缓存)。 普遍的缓存案例:

- - - -

针对一些特定的请求,也可以通过关键字区分多个存储的不同响应以组成缓存的内容。具体参考下文关于 {{HTTPHeader("Vary")}} 的信息。

- -

缓存控制

- -

Cache-control

- -

HTTP/1.1定义的 {{HTTPHeader("Cache-Control")}} 头用来区分对缓存机制的支持情况, 请求头和响应头都支持这个属性。通过它提供的不同的值来定义缓存策略。

- -

没有缓存

- -

缓存中不得存储任何关于客户端请求和服务端响应的内容。每次由客户端发起的请求都会下载完整的响应内容。

- -
Cache-Control: no-store
- -

缓存但重新验证

- -

如下头部定义,此方式下,每次有请求发出时,缓存会将此请求发到服务器(译者注:该请求应该会带有与本地缓存相关的验证字段),服务器端会验证请求中所描述的缓存是否过期,若未过期(注:实际就是返回304),则缓存才使用本地缓存副本。

- -
Cache-Control: no-cache
- -

私有和公共缓存

- -

"public" 指令表示该响应可以被任何中间人(译者注:比如中间代理、CDN等)缓存。若指定了"public",则一些通常不被中间人缓存的页面(译者注:因为默认是private)(比如 带有HTTP验证信息(帐号密码)的页面 或 某些特定状态码的页面),将会被其缓存。

- -

而 "private" 则表示该响应是专用于某单个用户的,中间人不能缓存此响应,该响应只能应用于浏览器私有缓存中。

- -
Cache-Control: private
-Cache-Control: public
- -

过期

- -

过期机制中,最重要的指令是 "max-age=<seconds>",表示资源能够被缓存(保持新鲜)的最大时间。相对Expires而言,max-age是距离请求发起的时间的秒数。针对应用中那些不会改变的文件,通常可以手动设置一定的时长以保证缓存有效,例如图片、css、js等静态资源。

- -

详情看下文关于缓存有效性的内容。

- -
Cache-Control: max-age=31536000
- -

验证方式

- -

当使用了 "must-revalidate" 指令,那就意味着缓存在考虑使用一个陈旧的资源时,必须先验证它的状态,已过期的缓存将不被使用。详情看下文关于缓存校验的内容。

- -
Cache-Control: must-revalidate
- -

Pragma 头

- -

{{HTTPHeader("Pragma")}} 是HTTP/1.0标准中定义的一个header属性,请求中包含Pragma的效果跟在头信息中定义Cache-Control: no-cache相同,但是HTTP的响应头没有明确定义这个属性,所以它不能拿来完全替代HTTP/1.1中定义的Cache-control头。通常定义Pragma以向后兼容基于HTTP/1.0的客户端。

- -

新鲜度

- -

理论上来讲,当一个资源被缓存存储后,该资源应该可以被永久存储在缓存中。由于缓存只有有限的空间用于存储资源副本,所以缓存会定期地将一些副本删除,这个过程叫做缓存驱逐。另一方面,当服务器上面的资源进行了更新,那么缓存中的对应资源也应该被更新,由于HTTP是C/S模式的协议,服务器更新一个资源时,不可能直接通知客户端更新缓存,所以双方必须为该资源约定一个过期时间,在该过期时间之前,该资源(缓存副本)就是新鲜的,当过了过期时间后,该资源(缓存副本)则变为陈旧的驱逐算法用于将陈旧的资源(缓存副本)替换为新鲜的,注意,一个陈旧的资源(缓存副本)是不会直接被清除或忽略的,当客户端发起一个请求时,缓存检索到已有一个对应的陈旧资源(缓存副本),则缓存会先将此请求附加一个If-None-Match头,然后发给目标服务器,以此来检查该资源副本是否是依然还是算新鲜的,若服务器返回了 304 (Not Modified)(该响应不会有带有实体信息),则表示此资源副本是新鲜的,这样一来,可以节省一些带宽。若服务器通过 If-None-Match 或 If-Modified-Since判断后发现已过期,那么会带有该资源的实体内容返回。

- -

下面是上述缓存处理过程的一个图示:

- -

Show how a proxy cache acts when a doc is not cache, in the cache and fresh, in the cache and stale.

- -

对于含有特定头信息的请求,会去计算缓存寿命。比如Cache-control: max-age=N的头,相应的缓存的寿命就是N。通常情况下,对于不含这个属性的请求则会去查看是否包含Expires属性,通过比较Expires的值和头里面Date属性的值来判断是否缓存还有效。如果max-age和expires属性都没有,找找头里的Last-Modified信息。如果有,缓存的寿命就等于头里面Date的值减去Last-Modified的值除以10(注:根据rfc2626其实也就是乘以10%)。

- -

缓存失效时间计算公式如下:

- -
expirationTime = responseTime + freshnessLifetime - currentAge
- -

上式中,responseTime 表示浏览器接收到此响应的那个时间点。

- -

改进资源

- -

我们使用缓存的资源越多,网站的响应能力和性能就会越好。为了优化缓存,过期时间设置得尽量长是一种很好的策略。对于定期或者频繁更新的资源,这么做是比较稳妥的,但是对于那些长期不更新的资源会有点问题。这些固定的资源在一定时间内受益于这种长期保持的缓存策略,但一旦要更新就会很困难。特指网页上引入的一些js/css文件,当它们变动时需要尽快更新线上资源。

- -

web开发者发明了一种被 Steve Souders 称之为 revving 的技术[1] 。不频繁更新的文件会使用特定的命名方式:在URL后面(通常是文件名后面)会加上版本号。加上版本号后的资源就被视作一个完全新的独立的资源,同时拥有一年甚至更长的缓存过期时长。但是这么做也存在一个弊端,所有引用这个资源的地方都需要更新链接。web开发者们通常会采用自动化构建工具在实际工作中完成这些琐碎的工作。当低频更新的资源(js/css)变动了,只用在高频变动的资源文件(html)里做入口的改动。

- -

这种方法还有一个好处:同时更新两个缓存资源不会造成部分缓存先更新而引起新旧文件内容不一致。对于互相有依赖关系的css和js文件,避免这种不一致性是非常重要的。

- -

- -

加在加速文件后面的版本号不一定是一个正式的版本号字符串,如1.1.3这样或者其他固定自增的版本数。它可以是任何防止缓存碰撞的标记例如hash或者时间戳。

- -

缓存验证

- -

用户点击刷新按钮时会开始缓存验证。如果缓存的响应头信息里含有"Cache-control: must-revalidate”的定义,在浏览的过程中也会触发缓存验证。另外,在浏览器偏好设置里设置Advanced->Cache为强制验证缓存也能达到相同的效果。

- -

当缓存的文档过期后,需要进行缓存验证或者重新获取资源。只有在服务器返回强校验器或者弱校验器时才会进行验证。

- -

ETags

- -

作为缓存的一种强校验器,{{HTTPHeader("ETag")}} 响应头是一个对用户代理(User Agent, 下面简称UA)不透明(译者注:UA 无需理解,只需要按规定使用即可)的值。对于像浏览器这样的HTTP UA,不知道ETag代表什么,不能预测它的值是多少。如果资源请求的响应头里含有ETag, 客户端可以在后续的请求的头中带上 {{HTTPHeader("If-None-Match")}} 头来验证缓存。

- -

{{HTTPHeader("Last-Modified")}} 响应头可以作为一种弱校验器。说它弱是因为它只能精确到一秒。如果响应头里含有这个信息,客户端可以在后续的请求中带上 {{HTTPHeader("If-Modified-Since")}} 来验证缓存。

- -

当向服务端发起缓存校验的请求时,服务端会返回 {{HTTPStatus(200)}} ok表示返回正常的结果或者 {{HTTPStatus(304)}} Not Modified(不返回body)表示浏览器可以使用本地缓存文件。304的响应头也可以同时更新缓存文档的过期时间。

- -

Vary 响应

- -

{{HTTPHeader("Vary")}} HTTP 响应头决定了对于后续的请求头,如何判断是请求一个新的资源还是使用缓存的文件。

- -

当缓存服务器收到一个请求,只有当前的请求和原始(缓存)的请求头跟缓存的响应头里的Vary都匹配,才能使用缓存的响应。

- -

The Vary header leads cache to use more HTTP headers as key for the cache.

- -

使用vary头有利于内容服务的动态多样性。例如,使用Vary: User-Agent头,缓存服务器需要通过UA判断是否使用缓存的页面。如果需要区分移动端和桌面端的展示内容,利用这种方式就能避免在不同的终端展示错误的布局。另外,它可以帮助 Google 或者其他搜索引擎更好地发现页面的移动版本,并且告诉搜索引擎没有引入Cloaking

- -
Vary: User-Agent
- -

因为移动版和桌面的客户端的请求头中的User-Agent不同, 缓存服务器不会错误地把移动端的内容输出到桌面端到用户。

- -

参考

- - - -
-
-
diff --git "a/files/zh-cn/web/http/content_negotiation/accept_\351\273\230\350\256\244\345\200\274/index.html" "b/files/zh-cn/web/http/content_negotiation/accept_\351\273\230\350\256\244\345\200\274/index.html" deleted file mode 100644 index 9db5868657..0000000000 --- "a/files/zh-cn/web/http/content_negotiation/accept_\351\273\230\350\256\244\345\200\274/index.html" +++ /dev/null @@ -1,248 +0,0 @@ ---- -title: Accept 默认值 -slug: Web/HTTP/Content_negotiation/Accept_默认值 -translation_of: Web/HTTP/Content_negotiation/List_of_default_Accept_values ---- -
{{HTTPSidebar}}
- -

本文介绍了在一些特定输入和浏览器版本下的HTTP  Accept 头的默认值

- -

默认值

- -

这些值将在上下文未设置其它信息时被使用。 注意:所有的浏览器都会添加 */* MIME 类型以涵盖各种情况。这通常用于通过浏览器的地址栏或HTML {{HTMLElement("a")}} 标签发起的请求。

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
User Agent Value Comment
Firefoxtext/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
-  
这个值可以通过network.http.accept.default 参数来修改。
Safari, Chrome -

application/xml,application/xhtml+xml,text/html;q=0.9, text/plain;q=0.8,image/png,*/*;q=0.5

-
source
Safari 5 -

text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8

-
这是对早期 Accept 头的改进,不再把 image/png 排在 text/html 之前。
Internet Explorer 8image/jpeg, application/x-ms-application, image/gif, application/xaml+xml, image/pjpeg, application/x-ms-xbap, application/x-shockwave-flash, application/msword, */* 请参见 IE and the Accept Header (IEInternals' MSDN blog).
Edgetext/html, application/xhtml+xml, image/jxr, */* 
Operatext/html, application/xml;q=0.9, application/xhtml+xml, image/png, image/webp, image/jpeg, image/gif, image/x-xbitmap, */*;q=0.1 
- -

image请求

- -

当请求一张图片时, 比如一个 HTML {{HTMLElement("img")}} 元素, 用户代理通常会设置一个特定的媒体类型列表。

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
User AgentValueComment
Firefox*/* (since Firefox 47)
- image/png,image/*;q=0.8,*/*;q=0.5 (before)
 这个值可以通过 image.http.accept 参数修改。
Safari*/* 
Chromeimage/webp,image/*,*/*;q=0.8 在支持webp格式之前,是使用的 */*
Internet Explorer 8 及更早版本*/* 请参见 IE and the Accept Header (IEInternals' MSDN blog)
Internet Explorer 9image/png,image/svg+xml,image/*;q=0.8, */*;q=0.5请参见 Fiddler is better with Internet Explorer 9 (IEInternals' MSDN blog)
- -

video请求

- -

通过HTML {{HTMLElement("video")}} 元素请求一个video时, 大多数浏览器会使用特定值。

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
User AgentValueComment
Firefox  3.6 之前的版本 不支持 {{HTMLElement("video")}} 
Firefox 3.6 及以上版本audio/webm, audio/ogg, audio/wav, audio/*;q=0.9, application/ogg;q=0.7, video/*;q=0.6; */*;q=0.5 请参见bug 489071
Chrome*/* 
Internet Explorer 8 或更早的版本 不支持 {{HTMLElement("video")}} 
- -

audio请求

- -

通过HTML {{HTMLElement("audio")}} 元素请求audio资源时, 大多数浏览器会使用特定值。

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
User AgentValueComment
Firefox 3.6 及以上版本audio/webm,audio/ogg,audio/wav,audio/*;q=0.9,application/ogg;q=0.7,video/*;q=0.6,*/*;q=0.5See bug 489071
Safari, Chrome? 
Internet Explorer 8 及更早版本 不支持 {{HTMLElement("audio")}} 
Internet Explorer 9? 
- -

scripts请求

- -

当通过 {{HTMLElement("script")}} 元素请求script时, 一些浏览器使用特定值。

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
User AgentValueComment
Firefox*/* 请参见bug 170789
Safari, Chrome*/* 
Internet Explorer 8 及更早版本*/*请参见 IE and the Accept Header (IEInternals' MSDN blog)
Internet Explorer 9application/javascript, */*;q=0.8请参见 Fiddler is better with Internet Explorer 9 (IEInternals' MSDN blog)
- -

CSS 请求

- -

当通过 <link rel="stylesheet"> HTML 元素请求CSS样式表时, 大多数浏览器使用特定值。

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
User AgentValueComment
Firefox 4text/css,*/*;q=0.1 请参见bug 170789
Safari 5text/css,*/*;q=0.1 
Internet Explorer 8 及更早版本*/*请参见 IE and the Accept Header (IEInternals' MSDN blog)
Internet Explorer 9text/css请参见 Fiddler is better with Internet Explorer 9 (IEInternals' MSDN blog)
Chrome 12text/css,*/*;q=0.1 
Opera 11.10text/html, application/xml;q=0.9, application/xhtml+xml, image/png, image/webp, image/jpeg, image/gif, image/x-xbitmap, */*;q=0.1  
Konqueror 4.6text/css,*/*;q=0.1 
diff --git a/files/zh-cn/web/http/content_negotiation/list_of_default_accept_values/index.html b/files/zh-cn/web/http/content_negotiation/list_of_default_accept_values/index.html new file mode 100644 index 0000000000..9db5868657 --- /dev/null +++ b/files/zh-cn/web/http/content_negotiation/list_of_default_accept_values/index.html @@ -0,0 +1,248 @@ +--- +title: Accept 默认值 +slug: Web/HTTP/Content_negotiation/Accept_默认值 +translation_of: Web/HTTP/Content_negotiation/List_of_default_Accept_values +--- +
{{HTTPSidebar}}
+ +

本文介绍了在一些特定输入和浏览器版本下的HTTP  Accept 头的默认值

+ +

默认值

+ +

这些值将在上下文未设置其它信息时被使用。 注意:所有的浏览器都会添加 */* MIME 类型以涵盖各种情况。这通常用于通过浏览器的地址栏或HTML {{HTMLElement("a")}} 标签发起的请求。

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
User Agent Value Comment
Firefoxtext/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
+  
这个值可以通过network.http.accept.default 参数来修改。
Safari, Chrome +

application/xml,application/xhtml+xml,text/html;q=0.9, text/plain;q=0.8,image/png,*/*;q=0.5

+
source
Safari 5 +

text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8

+
这是对早期 Accept 头的改进,不再把 image/png 排在 text/html 之前。
Internet Explorer 8image/jpeg, application/x-ms-application, image/gif, application/xaml+xml, image/pjpeg, application/x-ms-xbap, application/x-shockwave-flash, application/msword, */* 请参见 IE and the Accept Header (IEInternals' MSDN blog).
Edgetext/html, application/xhtml+xml, image/jxr, */* 
Operatext/html, application/xml;q=0.9, application/xhtml+xml, image/png, image/webp, image/jpeg, image/gif, image/x-xbitmap, */*;q=0.1 
+ +

image请求

+ +

当请求一张图片时, 比如一个 HTML {{HTMLElement("img")}} 元素, 用户代理通常会设置一个特定的媒体类型列表。

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
User AgentValueComment
Firefox*/* (since Firefox 47)
+ image/png,image/*;q=0.8,*/*;q=0.5 (before)
 这个值可以通过 image.http.accept 参数修改。
Safari*/* 
Chromeimage/webp,image/*,*/*;q=0.8 在支持webp格式之前,是使用的 */*
Internet Explorer 8 及更早版本*/* 请参见 IE and the Accept Header (IEInternals' MSDN blog)
Internet Explorer 9image/png,image/svg+xml,image/*;q=0.8, */*;q=0.5请参见 Fiddler is better with Internet Explorer 9 (IEInternals' MSDN blog)
+ +

video请求

+ +

通过HTML {{HTMLElement("video")}} 元素请求一个video时, 大多数浏览器会使用特定值。

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
User AgentValueComment
Firefox  3.6 之前的版本 不支持 {{HTMLElement("video")}} 
Firefox 3.6 及以上版本audio/webm, audio/ogg, audio/wav, audio/*;q=0.9, application/ogg;q=0.7, video/*;q=0.6; */*;q=0.5 请参见bug 489071
Chrome*/* 
Internet Explorer 8 或更早的版本 不支持 {{HTMLElement("video")}} 
+ +

audio请求

+ +

通过HTML {{HTMLElement("audio")}} 元素请求audio资源时, 大多数浏览器会使用特定值。

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
User AgentValueComment
Firefox 3.6 及以上版本audio/webm,audio/ogg,audio/wav,audio/*;q=0.9,application/ogg;q=0.7,video/*;q=0.6,*/*;q=0.5See bug 489071
Safari, Chrome? 
Internet Explorer 8 及更早版本 不支持 {{HTMLElement("audio")}} 
Internet Explorer 9? 
+ +

scripts请求

+ +

当通过 {{HTMLElement("script")}} 元素请求script时, 一些浏览器使用特定值。

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
User AgentValueComment
Firefox*/* 请参见bug 170789
Safari, Chrome*/* 
Internet Explorer 8 及更早版本*/*请参见 IE and the Accept Header (IEInternals' MSDN blog)
Internet Explorer 9application/javascript, */*;q=0.8请参见 Fiddler is better with Internet Explorer 9 (IEInternals' MSDN blog)
+ +

CSS 请求

+ +

当通过 <link rel="stylesheet"> HTML 元素请求CSS样式表时, 大多数浏览器使用特定值。

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
User AgentValueComment
Firefox 4text/css,*/*;q=0.1 请参见bug 170789
Safari 5text/css,*/*;q=0.1 
Internet Explorer 8 及更早版本*/*请参见 IE and the Accept Header (IEInternals' MSDN blog)
Internet Explorer 9text/css请参见 Fiddler is better with Internet Explorer 9 (IEInternals' MSDN blog)
Chrome 12text/css,*/*;q=0.1 
Opera 11.10text/html, application/xml;q=0.9, application/xhtml+xml, image/png, image/webp, image/jpeg, image/gif, image/x-xbitmap, */*;q=0.1  
Konqueror 4.6text/css,*/*;q=0.1 
diff --git a/files/zh-cn/web/http/cors/errors/corsmissingallowcredentials/index.html b/files/zh-cn/web/http/cors/errors/corsmissingallowcredentials/index.html new file mode 100644 index 0000000000..8a8f8d0074 --- /dev/null +++ b/files/zh-cn/web/http/cors/errors/corsmissingallowcredentials/index.html @@ -0,0 +1,32 @@ +--- +title: 故:在CORS头Access-Control-Allow-Credentials中预期为true +slug: Web/HTTP/CORS/Errors/CORS错误允许凭证 +translation_of: Web/HTTP/CORS/Errors/CORSMIssingAllowCredentials +--- +
+ +

理由

+ +
故:在CORS头Access-Control-Allow-Credentials中预期设为true
+ +

错在了哪儿?

+ +

     CORS请求要求服务器允许使用凭据,但是服务器的HTTPHeader:Access-Control-Allow-Credentials标头的值并没有设置为true 。

+ +

想要在客户端解决此问题,请修改代码以不请求使用凭据:

+ + + +

想要通过更改服务器的配置来消除此错误,请调整服务器的配置以将Access-Control-Allow-Credentials标头的值设置为true。

+ +

更多

+ + diff --git "a/files/zh-cn/web/http/cors/errors/cors\351\224\231\350\257\257\345\205\201\350\256\270\345\207\255\350\257\201/index.html" "b/files/zh-cn/web/http/cors/errors/cors\351\224\231\350\257\257\345\205\201\350\256\270\345\207\255\350\257\201/index.html" deleted file mode 100644 index 8a8f8d0074..0000000000 --- "a/files/zh-cn/web/http/cors/errors/cors\351\224\231\350\257\257\345\205\201\350\256\270\345\207\255\350\257\201/index.html" +++ /dev/null @@ -1,32 +0,0 @@ ---- -title: 故:在CORS头Access-Control-Allow-Credentials中预期为true -slug: Web/HTTP/CORS/Errors/CORS错误允许凭证 -translation_of: Web/HTTP/CORS/Errors/CORSMIssingAllowCredentials ---- -
- -

理由

- -
故:在CORS头Access-Control-Allow-Credentials中预期设为true
- -

错在了哪儿?

- -

     CORS请求要求服务器允许使用凭据,但是服务器的HTTPHeader:Access-Control-Allow-Credentials标头的值并没有设置为true 。

- -

想要在客户端解决此问题,请修改代码以不请求使用凭据:

- - - -

想要通过更改服务器的配置来消除此错误,请调整服务器的配置以将Access-Control-Allow-Credentials标头的值设置为true。

- -

更多

- - diff --git a/files/zh-cn/web/http/cors/index.html b/files/zh-cn/web/http/cors/index.html new file mode 100644 index 0000000000..c7acc1344d --- /dev/null +++ b/files/zh-cn/web/http/cors/index.html @@ -0,0 +1,510 @@ +--- +title: 跨源资源共享(CORS) +slug: Web/HTTP/Access_control_CORS +tags: + - AJAX + - CORS + - Cross-Origin Resource Sharing + - Fetch + - Fetch API + - HTTP + - HTTP Access Controls + - Same-origin policy + - Security + - XMLHttpRequest + - 'l10n:priority' +translation_of: Web/HTTP/CORS +--- +
{{HTTPSidebar}}
+ +

跨源资源共享 ({{Glossary("CORS")}}) (或通俗地译为跨域资源共享)是一种基于{{Glossary("HTTP")}} 头的机制,该机制通过允许服务器标示除了它自己以外的其它{{glossary("origin")}}(域,协议和端口),这样浏览器可以访问加载这些资源。跨源资源共享还通过一种机制来检查服务器是否会允许要发送的真实请求,该机制通过浏览器发起一个到服务器托管的跨源资源的"预检"请求。在预检中,浏览器发送的头中标示有HTTP方法和真实请求中会用到的头。

+ +

跨源HTTP请求的一个例子:运行在 http://domain-a.com 的JavaScript代码使用{{domxref("XMLHttpRequest")}}来发起一个到 https://domain-b.com/data.json 的请求。

+ +

出于安全性,浏览器限制脚本内发起的跨源HTTP请求。 例如,XMLHttpRequest和Fetch API遵循同源策略。 这意味着使用这些API的Web应用程序只能从加载应用程序的同一个域请求HTTP资源,除非响应报文包含了正确CORS响应头。

+ +

+ +

跨源域资源共享( {{Glossary("CORS")}} )机制允许 Web 应用服务器进行跨源访问控制,从而使跨源数据传输得以安全进行。现代浏览器支持在 API 容器中(例如 {{domxref("XMLHttpRequest")}} 或 Fetch )使用 CORS,以降低跨源 HTTP 请求所带来的风险。

+ +

谁应该读这篇文章?

+ +

说实话,每个人。

+ +

更具体地来讲,这篇文章适用于网站管理员、后端和前端开发者。现代浏览器处理跨源资源共享的客户端部分,包括HTTP头和相关策略的执行。但是这一新标准意味着服务器需要处理新的请求头和响应头。对于服务端的支持,开发者可以阅读补充材料 cross-origin sharing from a server perspective (with PHP code snippets)

+ +

什么情况下需要 CORS ?

+ +

这份 cross-origin sharing standard 允许在下列场景中使用跨站点 HTTP 请求:

+ + + +

本文概述了跨源资源共享机制及其所涉及的 HTTP 头。

+ +

功能概述

+ +

跨源资源共享标准新增了一组 HTTP 首部字段,允许服务器声明哪些源站通过浏览器有权限访问哪些资源。另外,规范要求,对那些可能对服务器数据产生副作用的 HTTP 请求方法(特别是 {{HTTPMethod("GET")}} 以外的 HTTP 请求,或者搭配某些 MIME 类型的 {{HTTPMethod("POST")}} 请求),浏览器必须首先使用 {{HTTPMethod("OPTIONS")}} 方法发起一个预检请求(preflight request),从而获知服务端是否允许该跨源请求。服务器确认允许之后,才发起实际的 HTTP 请求。在预检请求的返回中,服务器端也可以通知客户端,是否需要携带身份凭证(包括 Cookies 和 HTTP 认证相关数据)。

+ +

CORS请求失败会产生错误,但是为了安全,在JavaScript代码层面是无法获知到底具体是哪里出了问题。你只能查看浏览器的控制台以得知具体是哪里出现了错误。

+ +

接下来的内容将讨论相关场景,并剖析该机制所涉及的 HTTP 首部字段。

+ +

若干访问控制场景

+ +

这里,我们使用三个场景来解释跨源资源共享机制的工作原理。这些例子都使用 {{domxref("XMLHttpRequest")}} 对象。

+ +

本文中的 JavaScript 代码片段都可以从 http://arunranga.com/examples/access-control/ 获得。另外,使用支持跨源  {{domxref("XMLHttpRequest")}} 的浏览器访问该地址,可以看到代码的实际运行结果。

+ +

关于服务端对跨源资源共享的支持的讨论,请参见这篇文章: Server-Side_Access_Control (CORS)

+ +

简单请求

+ +

某些请求不会触发 CORS 预检请求。本文称这样的请求为“简单请求”,请注意,该术语并不属于 {{SpecName('Fetch')}} (其中定义了 CORS)规范。若请求满足所有下述条件,则该请求可视为“简单请求”:

+ + + +
注意: 这些跨站点请求与浏览器发出的其他跨站点请求并无二致。如果服务器未返回正确的响应首部,则请求方不会收到任何数据。因此,那些不允许跨站点请求的网站无需为这一新的 HTTP 访问控制特性担心。
+ +
注意: WebKit Nightly 和 Safari Technology Preview 为{{HTTPHeader("Accept")}}, {{HTTPHeader("Accept-Language")}}, 和 {{HTTPHeader("Content-Language")}} 首部字段的值添加了额外的限制。如果这些首部字段的值是“非标准”的,WebKit/Safari 就不会将这些请求视为“简单请求”。WebKit/Safari 并没有在文档中列出哪些值是“非标准”的,不过我们可以在这里找到相关讨论:Require preflight for non-standard CORS-safelisted request headers Accept, Accept-Language, and Content-Language, Allow commas in Accept, Accept-Language, and Content-Language request headers for simple CORS, and Switch to a blacklist model for restricted Accept headers in simple CORS requests。其它浏览器并不支持这些额外的限制,因为它们不属于规范的一部分。
+ +

比如说,假如站点 http://foo.example 的网页应用想要访问 http://bar.other 的资源。http://foo.example 的网页中可能包含类似于下面的 JavaScript 代码:

+ +
var invocation = new XMLHttpRequest();
+var url = 'http://bar.other/resources/public-data/';
+
+function callOtherDomain() {
+  if(invocation) {
+    invocation.open('GET', url, true);
+    invocation.onreadystatechange = handler;
+    invocation.send();
+  }
+}
+
+ +

客户端和服务器之间使用 CORS 首部字段来处理权限:

+ +

+ +

分别检视请求报文和响应报文:

+ +
GET /resources/public-data/ HTTP/1.1
+Host: bar.other
+User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre
+Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
+Accept-Language: en-us,en;q=0.5
+Accept-Encoding: gzip,deflate
+Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
+Connection: keep-alive
+Referer: http://foo.example/examples/access-control/simpleXSInvocation.html
+Origin: http://foo.example
+
+
+HTTP/1.1 200 OK
+Date: Mon, 01 Dec 2008 00:23:53 GMT
+Server: Apache/2.0.61
+Access-Control-Allow-Origin: *
+Keep-Alive: timeout=2, max=100
+Connection: Keep-Alive
+Transfer-Encoding: chunked
+Content-Type: application/xml
+
+[XML Data]
+
+ +

第 1~10 行是请求首部。第10行 的请求首部字段 {{HTTPHeader("Origin")}} 表明该请求来源于 http://foo.example

+ +

第 13~22 行是来自于 http://bar.other 的服务端响应。响应中携带了响应首部字段 {{HTTPHeader("Access-Control-Allow-Origin")}}(第 16 行)。使用 {{HTTPHeader("Origin")}} 和 {{HTTPHeader("Access-Control-Allow-Origin")}} 就能完成最简单的访问控制。本例中,服务端返回的 Access-Control-Allow-Origin: * 表明,该资源可以被任意外域访问。如果服务端仅允许来自 http://foo.example 的访问,该首部字段的内容如下:

+ +

Access-Control-Allow-Origin: http://foo.example

+ +

现在,除了 http://foo.example,其它外域均不能访问该资源(该策略由请求首部中的 ORIGIN 字段定义,见第10行)。Access-Control-Allow-Origin 应当为 * 或者包含由 Origin 首部字段所指明的域名。

+ +

预检请求

+ +

与前述简单请求不同,“需预检的请求”要求必须首先使用 {{HTTPMethod("OPTIONS")}}   方法发起一个预检请求到服务器,以获知服务器是否允许该实际请求。"预检请求“的使用,可以避免跨域请求对服务器的用户数据产生未预期的影响。

+ +

如下是一个需要执行预检请求的 HTTP 请求:

+ +
var invocation = new XMLHttpRequest();
+var url = 'http://bar.other/resources/post-here/';
+var body = '<?xml version="1.0"?><person><name>Arun</name></person>';
+
+function callOtherDomain(){
+  if(invocation)
+    {
+      invocation.open('POST', url, true);
+      invocation.setRequestHeader('X-PINGOTHER', 'pingpong');
+      invocation.setRequestHeader('Content-Type', 'application/xml');
+      invocation.onreadystatechange = handler;
+      invocation.send(body);
+    }
+}
+
+......
+
+ +

上面的代码使用 POST 请求发送一个 XML 文档,该请求包含了一个自定义的请求首部字段(X-PINGOTHER: pingpong)。另外,该请求的 Content-Type 为 application/xml。因此,该请求需要首先发起“预检请求”。

+ +

+ +
OPTIONS /resources/post-here/ HTTP/1.1
+Host: bar.other
+User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre
+Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
+Accept-Language: en-us,en;q=0.5
+Accept-Encoding: gzip,deflate
+Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
+Connection: keep-alive
+Origin: http://foo.example
+Access-Control-Request-Method: POST
+Access-Control-Request-Headers: X-PINGOTHER, Content-Type
+
+
+HTTP/1.1 200 OK
+Date: Mon, 01 Dec 2008 01:15:39 GMT
+Server: Apache/2.0.61 (Unix)
+Access-Control-Allow-Origin: http://foo.example
+Access-Control-Allow-Methods: POST, GET, OPTIONS
+Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
+Access-Control-Max-Age: 86400
+Vary: Accept-Encoding, Origin
+Content-Encoding: gzip
+Content-Length: 0
+Keep-Alive: timeout=2, max=100
+Connection: Keep-Alive
+Content-Type: text/plain
+ +

预检请求完成之后,发送实际请求:

+ +
POST /resources/post-here/ HTTP/1.1
+Host: bar.other
+User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre
+Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
+Accept-Language: en-us,en;q=0.5
+Accept-Encoding: gzip,deflate
+Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
+Connection: keep-alive
+X-PINGOTHER: pingpong
+Content-Type: text/xml; charset=UTF-8
+Referer: http://foo.example/examples/preflightInvocation.html
+Content-Length: 55
+Origin: http://foo.example
+Pragma: no-cache
+Cache-Control: no-cache
+
+<?xml version="1.0"?><person><name>Arun</name></person>
+
+
+HTTP/1.1 200 OK
+Date: Mon, 01 Dec 2008 01:15:40 GMT
+Server: Apache/2.0.61 (Unix)
+Access-Control-Allow-Origin: http://foo.example
+Vary: Accept-Encoding, Origin
+Content-Encoding: gzip
+Content-Length: 235
+Keep-Alive: timeout=2, max=99
+Connection: Keep-Alive
+Content-Type: text/plain
+
+[Some GZIP'd payload]
+ +

浏览器检测到,从 JavaScript 中发起的请求需要被预检。从上面的报文中,我们看到,第 1~12 行发送了一个使用 OPTIONS 方法的“预检请求”。 OPTIONS 是 HTTP/1.1 协议中定义的方法,用以从服务器获取更多信息。该方法不会对服务器资源产生影响。 预检请求中同时携带了下面两个首部字段:

+ +
Access-Control-Request-Method: POST
+Access-Control-Request-Headers: X-PINGOTHER, Content-Type
+ +

首部字段 {{HTTPHeader("Access-Control-Request-Method")}} 告知服务器,实际请求将使用 POST 方法。首部字段 {{HTTPHeader("Access-Control-Request-Headers")}} 告知服务器,实际请求将携带两个自定义请求首部字段:X-PINGOTHERContent-Type。服务器据此决定,该实际请求是否被允许。

+ +

第14~26 行为预检请求的响应,表明服务器将接受后续的实际请求。重点看第 17~20 行:

+ +
Access-Control-Allow-Origin: http://foo.example
+Access-Control-Allow-Methods: POST, GET, OPTIONS
+Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
+Access-Control-Max-Age: 86400
+ +

首部字段 Access-Control-Allow-Methods 表明服务器允许客户端使用 POST, GET OPTIONS 方法发起请求。该字段与 HTTP/1.1 Allow: response header 类似,但仅限于在需要访问控制的场景中使用。

+ +

首部字段 Access-Control-Allow-Headers 表明服务器允许请求中携带字段 X-PINGOTHER Content-Type Access-Control-Allow-Methods 一样,Access-Control-Allow-Headers 的值为逗号分割的列表。

+ +

最后,首部字段 Access-Control-Max-Age 表明该响应的有效时间为 86400 秒,也就是 24 小时。在有效时间内,浏览器无须为同一请求再次发起预检请求。请注意,浏览器自身维护了一个最大有效时间,如果该首部字段的值超过了最大有效时间,将不会生效。

+ +

预检请求与重定向

+ +

大多数浏览器不支持针对于预检请求的重定向。如果一个预检请求发生了重定向,浏览器将报告错误:

+ +
+

The request was redirected to 'https://example.com/foo', which is disallowed for cross-origin requests that require preflight

+
+ +
+

Request requires preflight, which is disallowed to follow cross-origin redirect

+
+ +

CORS 最初要求该行为,不过在后续的修订中废弃了这一要求

+ +

在浏览器的实现跟上规范之前,有两种方式规避上述报错行为:

+ + + +

如果上面两种方式难以做到,我们仍有其他办法:

+ + + +

不过,如果请求是由于存在 Authorization 字段而引发了预检请求,则这一方法将无法使用。这种情况只能由服务端进行更改。

+ +

附带身份凭证的请求

+ +

{{domxref("XMLHttpRequest")}} 或 Fetch 与 CORS 的一个有趣的特性是,可以基于  HTTP cookies 和 HTTP 认证信息发送身份凭证。一般而言,对于跨源 {{domxref("XMLHttpRequest")}} 或 Fetch 请求,浏览器不会发送身份凭证信息。如果要发送凭证信息,需要设置 XMLHttpRequest 的某个特殊标志位。

+ +

本例中,http://foo.example 的某脚本向 http://bar.other 发起一个GET 请求,并设置 Cookies:

+ +
var invocation = new XMLHttpRequest();
+var url = 'http://bar.other/resources/credentialed-content/';
+
+function callOtherDomain(){
+  if(invocation) {
+    invocation.open('GET', url, true);
+    invocation.withCredentials = true;
+    invocation.onreadystatechange = handler;
+    invocation.send();
+  }
+}
+ +

第 7 行将 XMLHttpRequest 的 withCredentials 标志设置为 true,从而向服务器发送 Cookies。因为这是一个简单 GET 请求,所以浏览器不会对其发起“预检请求”。但是,如果服务器端的响应中未携带 Access-Control-Allow-Credentials: true ,浏览器将不会把响应内容返回给请求的发送者。

+ +

+ +

客户端与服务器端交互示例如下:

+ +
GET /resources/access-control-with-credentials/ HTTP/1.1
+Host: bar.other
+User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre
+Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
+Accept-Language: en-us,en;q=0.5
+Accept-Encoding: gzip,deflate
+Connection: keep-alive
+Referer: http://foo.example/examples/credential.html
+Origin: http://foo.example
+Cookie: pageAccess=2
+
+
+HTTP/1.1 200 OK
+Date: Mon, 01 Dec 2008 01:34:52 GMT
+Server: Apache/2
+Access-Control-Allow-Origin: http://foo.example
+Access-Control-Allow-Credentials: true
+Cache-Control: no-cache
+Pragma: no-cache
+Set-Cookie: pageAccess=3; expires=Wed, 31-Dec-2008 01:34:53 GMT
+Vary: Accept-Encoding, Origin
+Content-Encoding: gzip
+Content-Length: 106
+Keep-Alive: timeout=2, max=100
+Connection: Keep-Alive
+Content-Type: text/plain
+
+
+[text/plain payload]
+ +

即使第 10 行指定了 Cookie 的相关信息,但是,如果 bar.other 的响应中缺失 {{HTTPHeader("Access-Control-Allow-Credentials")}}: true(第 17 行),则响应内容不会返回给请求的发起者。

+ +

附带身份凭证的请求与通配符

+ +

对于附带身份凭证的请求,服务器不得设置 Access-Control-Allow-Origin 的值为“*”。

+ +

这是因为请求的首部中携带了 Cookie 信息,如果 Access-Control-Allow-Origin 的值为“*”,请求将会失败。而将 Access-Control-Allow-Origin 的值设置为 http://foo.example,则请求将成功执行。

+ +

另外,响应首部中也携带了 Set-Cookie 字段,尝试对 Cookie 进行修改。如果操作失败,将会抛出异常。

+ +

第三方 cookies

+ +

注意在 CORS 响应中设置的 cookies 适用一般性第三方 cookie 策略。在上面的例子中,页面是在 `foo.example` 加载,但是第 20 行的 cookie 是被 `bar.other` 发送的,如果用户设置其浏览器拒绝所有第三方 cookies,那么将不会被保存。

+ +

HTTP 响应首部字段

+ +

本节列出了规范所定义的响应首部字段。上一小节中,我们已经看到了这些首部字段在实际场景中是如何工作的。

+ +

Access-Control-Allow-Origin

+ +

响应首部中可以携带一个 {{HTTPHeader("Access-Control-Allow-Origin")}} 字段,其语法如下:

+ +
Access-Control-Allow-Origin: <origin> | *
+
+ +

其中,origin 参数的值指定了允许访问该资源的外域 URI。对于不需要携带身份凭证的请求,服务器可以指定该字段的值为通配符,表示允许来自所有域的请求。

+ +

例如,下面的字段值将允许来自 http://mozilla.com 的请求:

+ +
Access-Control-Allow-Origin: http://mozilla.com
+ +

如果服务端指定了具体的域名而非“*”,那么响应首部中的 Vary 字段的值必须包含 Origin。这将告诉客户端:服务器对不同的源站返回不同的内容。

+ +

Access-Control-Expose-Headers

+ +

译者注:在跨源访问时,XMLHttpRequest对象的getResponseHeader()方法只能拿到一些最基本的响应头,Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma,如果要访问其他头,则需要服务器设置本响应头。

+ +

{{HTTPHeader("Access-Control-Expose-Headers")}} 头让服务器把允许浏览器访问的头放入白名单,例如:

+ +
Access-Control-Expose-Headers: X-My-Custom-Header, X-Another-Custom-Header
+
+ +

这样浏览器就能够通过getResponseHeader访问X-My-Custom-Header和 X-Another-Custom-Header 响应头了。

+ +

Access-Control-Max-Age

+ +

{{HTTPHeader("Access-Control-Max-Age")}} 头指定了preflight请求的结果能够被缓存多久,请参考本文在前面提到的preflight例子。

+ +
Access-Control-Max-Age: <delta-seconds>
+
+ +

delta-seconds 参数表示preflight请求的结果在多少秒内有效。

+ +

Access-Control-Allow-Credentials

+ +

{{HTTPHeader("Access-Control-Allow-Credentials")}} 头指定了当浏览器的credentials设置为true时是否允许浏览器读取response的内容。当用在对preflight预检测请求的响应中时,它指定了实际的请求是否可以使用credentials。请注意:简单 GET 请求不会被预检;如果对此类请求的响应中不包含该字段,这个响应将被忽略掉,并且浏览器也不会将相应内容返回给网页。

+ +
Access-Control-Allow-Credentials: true
+
+ +

上文已经讨论了附带身份凭证的请求

+ +

Access-Control-Allow-Methods

+ +

{{HTTPHeader("Access-Control-Allow-Methods")}} 首部字段用于预检请求的响应。其指明了实际请求所允许使用的 HTTP 方法。

+ +
Access-Control-Allow-Methods: <method>[, <method>]*
+
+ +

相关示例见这里

+ +

Access-Control-Allow-Headers

+ +

{{HTTPHeader("Access-Control-Allow-Headers")}} 首部字段用于预检请求的响应。其指明了实际请求中允许携带的首部字段。

+ +
Access-Control-Allow-Headers: <field-name>[, <field-name>]*
+
+ +

HTTP 请求首部字段

+ +

本节列出了可用于发起跨源请求的首部字段。请注意,这些首部字段无须手动设置。 当开发者使用 XMLHttpRequest 对象发起跨源请求时,它们已经被设置就绪。

+ +

Origin

+ +

{{HTTPHeader("Origin")}} 首部字段表明预检请求或实际请求的源站。

+ +
Origin: <origin>
+
+ +

origin 参数的值为源站 URI。它不包含任何路径信息,只是服务器名称。

+ +
Note: 有时候将该字段的值设置为空字符串是有用的,例如,当源站是一个 data URL 时。
+ +

注意,在所有访问控制请求(Access control request)中,{{HTTPHeader("Origin")}} 首部字段总是被发送。

+ +

Access-Control-Request-Method

+ +

{{HTTPHeader("Access-Control-Request-Method")}} 首部字段用于预检请求。其作用是,将实际请求所使用的 HTTP 方法告诉服务器。

+ +
Access-Control-Request-Method: <method>
+
+ +

相关示例见这里

+ +

Access-Control-Request-Headers

+ +

{{HTTPHeader("Access-Control-Request-Headers")}} 首部字段用于预检请求。其作用是,将实际请求所携带的首部字段告诉服务器。

+ +
Access-Control-Request-Headers: <field-name>[, <field-name>]*
+
+ +

相关示例见这里

+ +

规范

+ + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('Fetch', '#cors-protocol', 'CORS')}}{{Spec2('Fetch')}}New definition; supplants CORS specification.
{{SpecName('CORS')}}{{Spec2('CORS')}}Initial definition.
+ +

浏览器兼容性

+ + + +

{{Compat("http.headers.Access-Control-Allow-Origin")}}

+ +

+ + + +

参见

+ + + +

{{ languages( { "ja": "ja/HTTP_access_control" } ) }}

diff --git a/files/zh-cn/web/http/data_uris/index.html b/files/zh-cn/web/http/data_uris/index.html deleted file mode 100644 index 5153482967..0000000000 --- a/files/zh-cn/web/http/data_uris/index.html +++ /dev/null @@ -1,116 +0,0 @@ ---- -title: Data URLs -slug: Web/HTTP/data_URIs -tags: - - Base64 - - HTTP - - URL - - 教程 - - 进阶 -translation_of: Web/HTTP/Basics_of_HTTP/Data_URIs ---- -
{{HTTPSidebar}}
- -

Data URLs,即前缀为 data: 协议的URL,其允许内容创建者向文档中嵌入小文件。

- -

语法

- -

Data URLs 由四个部分组成:前缀(data:)、指示数据类型的MIME类型、如果非文本则为可选的base64标记、数据本身:

- -
data:[<mediatype>][;base64],<data>
-
- -

mediatype 是个 MIME 类型的字符串,例如 "image/jpeg" 表示 JPEG 图像文件。如果被省略,则默认值为 text/plain;charset=US-ASCII

- -

如果数据是文本类型,你可以直接将文本嵌入 (根据文档类型,使用合适的实体字符或转义字符)。如果是二进制数据,你可以将数据进行base64编码之后再进行嵌入。

- -

下面是一些示例:

- -
-
data:,Hello%2C%20World!
-
简单的 text/plain 类型数据
-
data:text/plain;base64,SGVsbG8sIFdvcmxkIQ%3D%3D
-
上一条示例的 base64 编码版本
-
data:text/html,%3Ch1%3EHello%2C%20World!%3C%2Fh1%3E
-
一个HTML文档源代码 <h1>Hello, World</h1>
-
data:text/html,<script>alert('hi');</script>
-
一个会执行 JavaScript alert 的 HTML 文档。注意 script 标签必须封闭。
-
- -

给数据作 base64 编码

- -

在Linux或者Mac OS系统上,你可以使用 uuencode 命令行工具来简单实现编码:

- -
uuencode -m infile remotename
-
- -

infile 参数表示要作 base64编码的文件名称,remotename 参数表示输出的文件名称, 实际上并没有在 data 方案的URLs 中使用。

- -

输出结果如下:

- -
begin-base64 664 test
-YSBzbGlnaHRseSBsb25nZXIgdGVzdCBmb3IgdGV2ZXIK
-====
-
- -

以上 Data URL 会使用位于首行之后的编码后的数据

- -

在网页上使用 JavaScript

- -

Web APIs 已经有对 base64 进行编码解码的方法: Base64 encoding and decoding.

- -

常见问题

- -

下文介绍一些在使用data URIs时遇到的常见问题:

- -
-
语法
-
data URLs 的格式很简单,但很容易会忘记把逗号加在 "data" 协议名后面,在对数据进行 base64 编码时也很容易发生错误。
-
HTML代码格式化
-
一个 data URL 是一个文件中的文件,相对于文档来说这个文件可能就非常的长。因为 data URL 也是 URL,所以 data 会用空白符(换行符, 制表符, 空格)来对它进行格式化。但如果数据是经过 base64 编码的,就可能会遇到一些问题
-
长度限制
-
虽然 Firefox 支持无限长度的 data URLs,但是标准中并没有规定浏览器必须支持任意长度的 data URIs。比如,Opera 11浏览器限制 URLs 最长为 65535 个字符,这意味着 data URLs 最长为 65529 个字符(如果你使用纯文本 data:, 而不是指定一个 MIME 类型的话,那么 65529 字符长度是编码后的长度,而不是源文件)。
-
缺乏错误处理
-
MIME类型错误或者base64编码错误,都会造成data URIs无法被正常解析, 但不会有任何相关错误提示.
-
不支持查询字符串
-
-

一个data URI的数据字段是没有结束标记的,所以尝试在一个data URI后面添加查询字符串会导致,查询字符串也一并被当作数据字段.例如:

- -
data:text/html,lots of text...<p><a name%3D"bottom">bottom</a>?arg=val
-
- -

这个 data URL 代表的 HTML 源文件内容为:

- -
lots of text...<p><a name="bottom">bottom</a>?arg=val
-
-
-
- -

浏览器兼容性

- -

{{compat("http.data-url")}}

- -

Specifications

- - - - - - - - - - - - -
SpecificationTitle
{{RFC("2397")}}The "data" URL scheme
- -

相关链接

- - diff --git a/files/zh-cn/web/http/feature_policy/index.html b/files/zh-cn/web/http/feature_policy/index.html new file mode 100644 index 0000000000..90e83fb04a --- /dev/null +++ b/files/zh-cn/web/http/feature_policy/index.html @@ -0,0 +1,153 @@ +--- +title: Feature Policy +slug: Web/HTTP/策略特征 +translation_of: Web/HTTP/Feature_Policy +--- +
{{SeeCompatTable}}{{HTTPSidebar}}
+ +

特征策略允许web开发者在浏览器中选择启用、禁用和修改确切特征和 API 的行为.比如{{Glossary("CSP","内容安全策略")}},但是它控制的是浏览器的特征非安全行为.

+ +

概述

+ +

特征策略提供了一种机制去声明哪些功能通过你的网络,是可以被用的(或者不被使用的)。这就允许你通过功能可用性来很好的锁定功能,即使代码很老,或者包含第三方的内容。

+ +

有了功能策略,你可以选择一组“策略”,让浏览器强制执行整个网站使用的特定功能。这些策略限制了站点可以访问哪些api,或者修改浏览器对某些特性的默认行为

+ +

使用特性策略可以做什么的示例?:

+ + + +

概念和用法

+ +

特性策略允许您在顶级页面和嵌入式框架中控制哪些源可以使用哪些特性。实际上,您编写了一个策略,它是每个特性允许的起源列表。对于由特性策略控制的每个特性,只有当它的起源与允许的起源列表匹配时,该特性才会在当前文档或框架中启用.

+ +

对于每个策略控制的功能,浏览器都会维护启用该功能的来源列表,称为允许列表。如果您未为功能指定策略,则将使用默认的允许列表。默认的许可列表特定于每个功能.

+ +

编写策略

+ +

使用一组单独的策略指令来描述策略。策略指令是已定义功能名称和可以使用该功能的来源的允许列表的组合.

+ +

指定策略

+ +

功能策略提供了两种方法来指定用于控制功能的策略:

+ + + +

HTTP标头和allow属性之间的主要区别在于allow属性仅控制iframe中的功能。标头控制响应中的功能以及页面内的任何嵌入式内容.

+ +

点此链接查看更多详细信息 Using Feature Policy.

+ +

策略控制功能的类型

+ +

尽管功能策略使用一致的语法提供了对多个功能的控制,但是策略控制功能的行为却有所不同,并取决于多个因素.

+ +

一般原则是,Web开发人员应该有一种直观或不间断的方式来检测或处理禁用该功能的情况。新引入的功能可能具有显示状态的显式API。稍后与功能策略集成的现有功能通常将使用现有机制。一些方法包括:

+ + + +

当前的一组策略控制功能可分为两大类:

+ + + +

良好用户体验的最佳实践

+ +

有几种策略控制的功能可帮助实施最佳实践,以提供良好的性能和用户体验.

+ +

在大多数情况下,策略控制的功能代表的功能在使用时会对用户体验产生负面影响。为避免破坏现有的Web内容,此类策略控制功能的默认设置是允许所有来源使用该功能。然后,通过使用禁用策略控制功能的策略来实施最佳实践。有关更多详细信息,请参见“实施最佳实践以提供良好的用户体验”.

+ +

功能包括:

+ + + +

精细控制某些功能

+ +

Web提供的功能和API如果被滥用,可能会带来隐私或安全风险。在某些情况下,您可能希望严格限制在网站上使用此类功能的方式。有策略控制的功能,允许针对网站中的特定来源或框架启用/禁用功能。该功能在可用时与Permissions API或特定于功能的机制集成在一起,以检查该功能是否可用.

+ +

功能包括:

+ + + +

更多示例

+ + + +

规范

+ + + + + + + + + + + + + + +
说明书状态描述
{{SpecName('Feature Policy','#feature-policy-http-header-field','Feature-Policy')}}{{Spec2('Feature Policy')}}初始化前定义 {{httpheader('Feature-Policy')}} 头. 规范中定义了指令所控制的特性. 有关详细信息,请参阅个别指令页面.
+ +

浏览器兼容性

+ + + +

{{Compat("http.headers.Feature-Policy")}}

+ +

参见

+ + diff --git a/files/zh-cn/web/http/feature_policy/using_feature_policy/index.html b/files/zh-cn/web/http/feature_policy/using_feature_policy/index.html new file mode 100644 index 0000000000..9a37fa46f3 --- /dev/null +++ b/files/zh-cn/web/http/feature_policy/using_feature_policy/index.html @@ -0,0 +1,140 @@ +--- +title: Using Feature Policy +slug: Web/HTTP/策略特征/Using_Feature_Policy +translation_of: Web/HTTP/Feature_Policy/Using_Feature_Policy +--- +
{{HTTPSidebar}} {{SeeCompatTable}}
+ +

Feature Policy allows you to control which origins can use which features, both in the top-level page and in embedded frames. Essentially, you write a policy, which is an allowed list of origins for each feature. For every feature controlled by Feature Policy, the feature is only enabled in the current document or frame if its origin matches the allowed list of origins.

+ +

For each policy-controlled feature, the browser maintains a list of origins for which the feature is enabled, known as an allowlist. If you do not specify a policy for a feature, then a default allowlist will be used. The default allowlist is specific to each feature.

+ +

Writing a policy

+ +

A policy is described using a set of individual policy directives. A policy directive is a combination of a defined feature name, and an allowlist of origins that can use the feature.

+ +

allowlist

+ +

allowlist可以使用以下一个或多个值。

+ + + +

*(在所有源地址启用)'none'(在所有源地址禁用)只允许单独使用,而'self''src'可以与多个源地址一起使用。

+ +

所有的特性都有一个如下的默认的allowlist

+ + + +

Specifying your policy

+ +

Feature Policy provides two ways to specify policies to control features:

+ + + +

The primary difference between the HTTP header and the allow attribute is that the allow attribute only controls features within an iframe. The header controls features in the response and any embedded content within the page.

+ +

The Feature-Policy HTTP header

+ +

You can send the Feature-Policy HTTP header with the response of a page. The value of this header is a policy to be enforced by the browser for the given page. It has the following structure.

+ +
Feature-Policy: <feature name> <allowlist of origin(s)>
+ +

For example, to block all content from using the Geolocation API across your site:

+ +
Feature-Policy: geolocation 'none'
+ +

Several features can be controlled at the same time by sending the HTTP header with a semicolon-separated list of policy directives, or by sending a separate header for each policy.

+ +

For example, the following are equivalent:

+ +
Feature-Policy: unsized-media 'none'; geolocation 'self' https://example.com; camera *;
+
+Feature-Policy: unsized-media 'none'
+Feature-Policy: geolocation 'self' https://example.com
+Feature-Policy: camera *;
+
+ +

The iframe allow attribute

+ +

The second way to use Feature Policy is for controlling content within an iframe. Use the allow attribute to specify a policy list for embedded content.

+ +

For example, allow all browsing contexts within this iframe to use fullscreen:

+ +
<iframe src="https://example.com..." allow="fullscreen"></iframe>
+ +

This is equivalent to:

+ +
<iframe src="https://example.com..." allow="fullscreen 'src'"></iframe>
+ +

This example allows <iframe> content on a particular origin to access the user's location:

+ +
<iframe src="https://google-developers.appspot.com/demos/..."
+        allow="geolocation https://google-developers.appspot.com"></iframe>
+
+ +

Similar to the HTTP header, several features can be controlled at the same time by specifying a semicolon-separated list of policy directives.

+ +

For example, this blocks the <iframe> from using the camera and microphone:

+ +
<iframe allow="camera 'none'; microphone 'none'">
+
+ +

Inheritance of policy for embedded content

+ +

Scripts inherit the policy of their browsing context, regardless of their origin. That means that top-level scripts inherit the policy from the main document.

+ +

All iframes inherit the policy of their parent page. If the iframe has an allow attribute, the policies of the parent page and the allow attribute are combined, using the most restrictive subset. For an iframe to have a feature enabled, the origin must be in the allowlist for both the parent page and the allow attribute.

+ +

Disabling a feature in a policy is a one-way toggle. If a feature has been disabled for a child frame by its parent frame, the child cannot re-enable it, and neither can any of the child's descendants.

+ +

Enforcing best practices for good user experiences

+ +

It's difficult to build a website that uses all the latest best practices and provides great performance and user experiences. As the website evolves, it can become even harder to maintain the user experience over time. You can use feature policies to specify the desired best practices, and rely on the browser to enforce the policies to prevent regressions.

+ +

There are several policy-controlled features designed to represent functionality that can negatively impact the user experience. These features include:

+ + + +

To avoid breaking existing web content, the default for such policy-controlled features is to allow the functionality to be used by all origins. That is, the default allowlist is '*' for each feature. Preventing the use of the sub-optimal functionality requires explicitly specifying a policy that disables the features.

+ +

For new content, you can start developing with a policy that disables all the features. This approach ensures that none of the functionality is introduced. When applying a policy to existing content, testing is likely required to verify it continues to work as expected. This is especially important for embedded or third-party content that you do not control.

+ +

To turn on the enforcement of all the best practices, specify the policy as below.

+ +

Send the following the HTTP header:

+ +
Feature-Policy: layout-animations 'none'; unoptimized-images 'none'; oversized-images 'none'; sync-script 'none'; sync-xhr 'none'; unsized-media 'none';
+ +

Using the <iframe> allow attribute:

+ +
<iframe src="https://example.com..." allow="layout-animations 'none'; unoptimized-images 'none'; oversized-images 'none'; sync-script 'none'; sync-xhr 'none'; unsized-media 'none';"></iframe>
+ +

See also

+ + diff --git a/files/zh-cn/web/http/headers/strict-transport-security/index.html b/files/zh-cn/web/http/headers/strict-transport-security/index.html new file mode 100644 index 0000000000..d890b429ef --- /dev/null +++ b/files/zh-cn/web/http/headers/strict-transport-security/index.html @@ -0,0 +1,121 @@ +--- +title: HTTP Strict Transport Security +slug: Web/HTTP/HTTP_Strict_Transport_Security +tags: + - HSTS + - HTTP + - HTTPS + - Security + - header +translation_of: Web/HTTP/Headers/Strict-Transport-Security +--- +
 HTTP Strict Transport Security(通常简称为{{Glossary("HSTS")}})是一个安全功能,它告诉浏览器只能通过HTTPS访问当前资源,而不是HTTP
+ + + + + + + + + + + + +
Header type{{Glossary("Response header")}}
{{Glossary("Forbidden header name")}}no
+ +

语法

+ +
Strict-Transport-Security: max-age=<expire-time>
+Strict-Transport-Security: max-age=<expire-time>; includeSubDomains
+Strict-Transport-Security: max-age=<expire-time>; preload
+
+ +

指令

+ +
+
max-age=<expire-time>
+
设置在浏览器收到这个请求后的<expire-time>秒的时间内凡是访问这个域名下的请求都使用HTTPS请求。
+
includeSubDomains {{optional_inline}}
+
如果这个可选的参数被指定,那么说明此规则也适用于该网站的所有子域名。
+
preload {{optional_inline}}
+
查看 {{anch("预加载 HSTS")}} 获得详情。不是标准的一部分。
+
+ +

描述

+ +

一个网站接受一个HTTP的请求,然后跳转到HTTPS,用户可能在开始跳转前,通过没有加密的方式和服务器对话,比如,用户输入http://foo.com或者直接foo.com。

+ +

这样存在中间人攻击潜在威胁,跳转过程可能被恶意网站利用来直接接触用户信息,而不是原来的加密信息。

+ +

网站通过HTTP Strict Transport Security通知浏览器,这个网站禁止使用HTTP方式加载,浏览器应该自动把所有尝试使用HTTP的请求自动替换为HTTPS请求。

+ +
+

注意: Strict-Transport-Security 在通过 HTTP 访问时会被浏览器忽略; 因为攻击者可以通过中间人攻击的方式在连接中修改、注入或删除它.  只有在你的网站通过HTTPS访问并且没有证书错误时, 浏览器才认为你的网站支持HTTPS 然后使用 Strict-Transport-Security 的值 .

+
+ +

浏览器如何处理

+ +

你的网站第一次通过HTTPS请求,服务器响应Strict-Transport-Security 头,浏览器记录下这些信息,然后后面尝试访问这个网站的请求都会自动把HTTP替换为HTTPS。

+ +

当HSTS头设置的过期时间到了,后面通过HTTP的访问恢复到正常模式,不会再自动跳转到HTTPS。

+ +

每次浏览器接收到Strict-Transport-Security头,它都会更新这个网站的过期时间,所以网站可以刷新这些信息,防止过期发生。

+ +

Chrome、Firefox等浏览器里,当您尝试访问该域名下的内容时,会产生一个307 Internal Redirect(内部跳转),自动跳转到HTTPS请求。

+ +

示例场景

+ +

你连接到一个免费WiFi接入点,然后开始浏览网站,访问你的网上银行,查看你的支出,并且支付一些订单。很不幸,你接入的WiFi实际上是黑客的笔记本热点,他们拦截了你最初的HTTP请求,然后跳转到一个你银行网站一模一样的钓鱼网站。 现在,你的隐私数据暴露给黑客了。

+ +

Strict Transport Security解决了这个问题;只要你通过HTTPS请求访问银行网站,并且银行网站配置好Strict Transport Security,你的浏览器知道自动使用HTTPS请求,这可以阻止黑客的中间人攻击的把戏。

+ +

预加载 HSTS

+ +

谷歌维护着一个 HSTS 预加载服务。按照如下指示成功提交你的域名后,浏览器将会永不使用非安全的方式连接到你的域名。虽然该服务是由谷歌提供的,但所有浏览器都有使用这份列表的意向(或者已经在用了)。但是,这不是 HSTS 标准的一部分,也不该被当作正式的内容。

+ + + +

示例

+ +

现在和未来的所有子域名会自动使用 HTTPS 连接长达一年。同时阻止了只能通过 HTTP 访问的内容。

+ +
Strict-Transport-Security: max-age=31536000; includeSubDomains
+
+ +

规范

+ + + + + + + + + + + + + + +
规范状态注释
{{SpecName('HSTS')}}{{Spec2('HSTS')}}Initial definition
+ +

浏览器兼容

+ + + +

{{Compat("http.headers.Strict-Transport-Security")}}

+ +

查看更多

+ + diff --git a/files/zh-cn/web/http/headers/x-dns-prefetch-control/index.html b/files/zh-cn/web/http/headers/x-dns-prefetch-control/index.html new file mode 100644 index 0000000000..313d309ccb --- /dev/null +++ b/files/zh-cn/web/http/headers/x-dns-prefetch-control/index.html @@ -0,0 +1,97 @@ +--- +title: X-DNS-Prefetch-Control +slug: Controlling_DNS_prefetching +tags: + - DNS + - DNS prefetch + - HTTP + - 预解析 +translation_of: Web/HTTP/Headers/X-DNS-Prefetch-Control +--- +

{{HTTPSidebar}}

+ +

X-DNS-Prefetch-Control 头控制着浏览器的 DNS 预读取功能。 DNS 预读取是一项使浏览器主动去执行域名解析的功能,其范围包括文档的所有链接,无论是图片的,CSS 的,还是 JavaScript 等其他用户能够点击的 URL。

+ +

因为预读取会在后台执行,所以 {{glossary("DNS")}} 很可能在链接对应的东西出现之前就已经解析完毕。这能够减少用户点击链接时的延迟。

+ + + + + + + + + + + + +
Header type{{Glossary("Response header")}}
{{Glossary("Forbidden header name")}}no
+ +

语法

+ +
X-DNS-Prefetch-Control: on
+X-DNS-Prefetch-Control: off
+
+ +

参数

+ +
+
on
+
启用 DNS 预解析。在浏览器支持 DNS 预解析的特性时即使不使用该标签浏览器依然会进行预解析。
+
off
+
关闭 DNS 预解析。这个属性在页面上的链接并不是由你控制的或是你根本不想向这些域名引导数据时是非常有用的。
+
+ +

介绍

+ +

DNS 请求需要的带宽非常小,但是延迟却有点高,这一点在手机网络上特别明显。预读取 DNS 能让延迟明显减少一些,例如在用户点击链接时。在某些情况下,延迟能减少一秒钟。 

+ +

在某些浏览器中这个预读取的行为将会与页面实际内容并行发生(而不是串行)。正因如此,某些高延迟的域名的解析过程才不会卡住资源的加载。

+ +

这样可以极大的加速(尤其是移动网络环境下)页面的加载。在某些图片较多的页面中,在发起图片加载请求之前预先把域名解析好将会有至少 5% 的图片加载速度提升。

+ +

在浏览器中设置预读取配置

+ +

一般来说并不需要去管理预读取,但是可能会有用户希望关闭预读取功能。这时只需要将 network.dns.disablePrefetch 选项值设置为 true 就可以了。

+ +

另外,默认情况下,通过 {{glossary("HTTPS")}} 加载的页面上内嵌链接的域名并不会执行预加载。在 Firefox 浏览器中,可以通过 about:config 设置 network.dns.disablePrefetchFromHTTPS 值为 false 来改变这一默认行为。

+ +

示例

+ +

打开和关闭 DNS 预读取

+ +

你可以通过在服务器端发送 X-DNS-Prefetch-Control 报头,或是在文档中使用值为 {{ htmlattrxref("http-equiv") }} 的 {{ HTMLElement("meta") }} 标签:

+ +
<meta http-equiv="x-dns-prefetch-control" content="off">
+
+ +

您可以通过将 content 的参数设置为“on”来改变设置。

+ +

强制查询特定主机名

+ +

你可以通过使用 {{ htmlattrxref("rel","link") }} 属性值为 link type 中的 dns-prefetch 的 {{ HTMLElement("link") }} 标签来对特定域名进行预读取:

+ +
<link rel="dns-prefetch" href="http://www.spreadfirefox.com/">
+
+ +

在这个例子中,Firefox 将预解析域名"www.spreadfirefox.com"。

+ +

而且,{{ HTMLElement("link") }} 元素也可以使用不完整的 URL 的主机名来标记预解析,但这些主机名前必需要有双斜线:

+ +
<link rel="dns-prefetch" href="//www.spreadfirefox.com">
+
+ +

强制对域名进行预读取在一些情况下很有用, 比如, 在网站的主页上,强制在整个网站上频繁引用的域名的预解析,即使它们不在主页本身上使用。即使主页的性能可能不受影响,这将提高整体站点性能。

+ +

浏览器兼容性

+ + + +

{{Compat("http.headers.X-DNS-Prefetch-Control")}}

+ +

参考

+ + diff --git a/files/zh-cn/web/http/headers/x-frame-options/index.html b/files/zh-cn/web/http/headers/x-frame-options/index.html new file mode 100644 index 0000000000..2b6cfcda76 --- /dev/null +++ b/files/zh-cn/web/http/headers/x-frame-options/index.html @@ -0,0 +1,161 @@ +--- +title: X-Frame-Options +slug: Web/HTTP/X-Frame-Options +tags: + - HTTP + - 响应头 + - 响应头部 + - 安全性 +translation_of: Web/HTTP/Headers/X-Frame-Options +--- +
{{HTTPSidebar}}
+ +

The X-Frame-Options HTTP 响应头是用来给浏览器 指示允许一个页面 可否在 {{HTMLElement("frame")}}, {{HTMLElement("iframe")}}, {{HTMLElement("embed")}} 或者 {{HTMLElement("object")}} 中展现的标记。站点可以通过确保网站没有被嵌入到别人的站点里面,从而避免 {{interwiki("wikipedia", "clickjacking")}} 攻击。

+ +

The added security is only provided if the user accessing the document is using a browser supporting X-Frame-Options. {{HTTPHeader("Content-Security-Policy")}} HTTP 头中的 frame-ancestors 指令会替代这个非标准的 header。CSP 的 frame-ancestors 会在 {{Gecko("4.0")}} 中支持,但是并不会被所有浏览器支持。然而 X-Frame-Options 是个已广泛支持的非官方标准,可以和 CSP 结合使用。

+ + + + + + + + + + + + +
Header type{{Glossary("Response header")}}
{{Glossary("Forbidden header name")}}no
+ +

语法

+ +

X-Frame-Options 有三个可能的值:

+ +
X-Frame-Options: deny
+X-Frame-Options: sameorigin
+X-Frame-Options: allow-from https://example.com/
+
+ +

指南

+ +

换一句话说,如果设置为 deny,不光在别人的网站 frame 嵌入时会无法加载,在同域名页面中同样会无法加载。另一方面,如果设置为sameorigin,那么页面就可以在同域名页面的 frame 中嵌套。

+ +
+
deny
+
表示该页面不允许在 frame 中展示,即便是在相同域名的页面中嵌套也不允许。
+
sameorigin
+
表示该页面可以在相同域名页面的 frame 中展示。
+
allow-from uri
+
表示该页面可以在指定来源的 frame 中展示。
+
+ +

例子

+ +
+

Note: 设置 meta 标签是无效的!例如 <meta http-equiv="X-Frame-Options" content="deny"> 没有任何效果。不要这样用!只有当像下面示例那样设置 HTTP 头 X-Frame-Options 才会生效。

+
+ +

配置 Apache

+ +

配置 Apache 在所有页面上发送 X-Frame-Options 响应头,需要把下面这行添加到 'site' 的配置中:

+ +
Header always set X-Frame-Options "sameorigin"
+
+ +

要将 Apache 的配置 X-Frame-Options 设置成 deny , 按如下配置去设置你的站点:

+ +
Header set X-Frame-Options "deny"
+
+ +

要将 Apache 的配置 X-Frame-Options 设置成 allow-from,在配置里添加:

+ +
Header set X-Frame-Options "allow-from https://example.com/"
+
+ +

配置 nginx

+ +

配置 nginx 发送 X-Frame-Options 响应头,把下面这行添加到 'http', 'server' 或者 'location' 的配置中:

+ +
add_header X-Frame-Options sameorigin always;
+
+ +

配置 IIS

+ +

配置 IIS 发送 X-Frame-Options 响应头,添加下面的配置到 Web.config 文件中:

+ +
<system.webServer>
+  ...
+
+  <httpProtocol>
+    <customHeaders>
+      <add name="X-Frame-Options" value="sameorigin" />
+    </customHeaders>
+  </httpProtocol>
+
+  ...
+</system.webServer>
+
+ +

配置 HAProxy

+ +

配置 HAProxy 发送 X-Frame-Options 头,添加这些到你的前端、监听 listen,或者后端的配置里面:

+ +
rspadd X-Frame-Options:\ sameorigin
+
+ +

或者,在更加新的版本中:

+ +
http-response set-header X-Frame-Options sameorigin
+
+ +

配置 Express

+ +

要配置 Express 可以发送 X-Frame-Options header,你可以用借助了 frameguard 来设置头部的 helmet。在你的服务器配置里面添加:

+ +
const helmet = require('helmet');
+const app = express();
+app.use(helmet.frameguard({ action: "sameorigin" }));
+
+ +

或者,你也可以直接用 frameguard

+ +
const frameguard = require('frameguard')
+app.use(frameguard({ action: 'sameorigin' }))
+
+ +

结果

+ +

在 Firefox 尝试加载 frame 的内容时,如果 X-Frame-Options 响应头设置为禁止访问了,那么 Firefox 会用 about:blank 展现到 frame 中。也许从某种方面来讲的话,展示为错误消息会更好一点。

+ +

规范

+ + + + + + + + + + + + + + +
规范标题
{{RFC("7034")}}HTTP Header Field X-Frame-Options
+ +

浏览器兼容性

+ + + +

{{Compat("http.headers.X-Frame-Options")}}

+ +

参见

+ + diff --git a/files/zh-cn/web/http/http_response_codes/index.html b/files/zh-cn/web/http/http_response_codes/index.html deleted file mode 100644 index 2c0fce1058..0000000000 --- a/files/zh-cn/web/http/http_response_codes/index.html +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: HTTP response codes -slug: Web/HTTP/HTTP_response_codes -translation_of: Web/HTTP/Status -translation_of_original: Web/HTTP/HTTP_response_codes ---- -

HTTP状态码(响应码)用来表明这个HTTP 请求是否已经成功完成.HTTP响应类型一共分五大类:消息响应,成功响应,重定向,客户端错误,服务器端错误.

-

 

-

下表列出了所有HTTP状态码,以及他们各自所代表的含义:

- -
状态码   原因短语 代表含义 HTTP 版本   
消息响应
100          Continue
(继续)
客户端应当继续发送请求.这个临时响应是用来通知客户端它的部分请求已经被服务器接收,且仍未被拒绝.客户端应当继续发送请求的剩余部分,或者如果请求已经完成,忽略这个响应.服务器必须在请求完成后向客户端发送一个最终响应. HTTP/1.1 可用
101 Switching Protocol
(切换协议)
服务器已经理解了客户端的请求,并将通过Upgrade消息头通知客户端采用不同的协议来完成这个请求。在发送完这个响应最后的空行后,服务器将会切换到 在Upgrade消息头中定义的那些协议。: 只有在切换新的协议更有好处的时候才应该采取类似措施。例如,切换到新的HTTP版本比旧版本更有优势,或者切换到一个实时且同步的协议以传送利用此类特 性的资源。 HTTP/1.1 可用
成功响应
200 OK
(成功)
请求成功.成功的意义根据请求所使用的方法不同而不同.
  • GET: 资源已被提取,并作为响应体传回客户端.
  • HEAD: 实体已作为响应头传回客户端
  • POST: 经过服务器处理客户端传来的数据,适合的资源作为响应体传回客户端.
  • TRACE: 服务器收到请求消息作为响应体传回客户端.
PUT, DELETE, 和 OPTIONS 方法永远不会返回 200 状态码.
HTTP/0.9 可用
201 Created
(已创建)
请求成功,而且有一个新的资源已经依据请求的需要而建立,通常这是 PUT 方法得到的响应码. HTTP/0.9 可用
202 Accepted
(已创建)
服务器已接受请求,但尚未处理。正如它可能被拒绝一样,最终该请求可能会也可能不会被执行。在异步操作的场合下,没有比发送这个状态码更方便的做法了。:返回202状态码的响应的目的是允许服务器接受其他过程的请求(例如某个每天只执行一次的基于批处理的操作),而不必让客户端一直保持与服务器的连接直到批处理操作全部完成。在接受请求处理并返回202状态码的响应应当在返回的实体中包含一些指示处理当前状态的信息,以及指向处理状态监视器或状态预测的指针,以便用户能够估计操作是否已经完成。 HTTP/0.9 可用
203 Non-Authoritative Information
(未授权信息)

服务器已成功处理了请求,但返回的实体头部元信息不是在原始服务器上有效的确定集合,而是来自本地或者第三方的拷贝,如果不是上述情况,使用200状态码才是最合适的.

HTTP/0.9 and 1.1
204 No Content
(无内容)
该响应没有响应内容,只有响应头,响应头也可能是有用的.用户代理可以根据新的响应头来更新对应资源的缓存信息. HTTP/0.9 可用
205 Reset Content
(重置内容)
告诉用户代理去重置发送该请求的窗口的文档视图. HTTP/1.1 可用
206 Partial Content
(部分内容)
当客户端通过使用range头字段进行文件分段下载时使用该状态码 HTTP/1.1 可用
重定向
300 Multiple Choice
(多种选择)
该请求有多种可能的响应,用户代理或者用户必须选择它们其中的一个.服务器没有任何标准可以遵循去代替用户来进行选择. HTTP/1.0 and later
301 Moved Permanently
(永久移动)
该状态码表示所请求的URI资源路径已经改变,新的URL会在响应的Location:头字段里找到. HTTP/0.9 可用
302 Found
(临时移动)
该状态码表示所请求的URI资源路径临时改变,并且还可能继续改变.因此客户端在以后访问时还得继续使用该URI.新的URL会在响应的Location:头字段里找到. HTTP/0.9 可用
303 See Other
(查看其他位置)
服务器发送该响应用来引导客户端使用GET方法访问另外一个URI. HTTP/0.9 and 1.1
304 Not Modified
(未修改)
告诉客户端,所请求的内容距离上次访问并没有变化. 客户端可以直接从浏览器缓存里获取该资源. HTTP/0.9 可用
305 Use Proxy
(使用代理)
所请求的资源必须统过代理才能访问到.由于安全原因,该状态码并未受到广泛支持. HTTP/1.1 可用
306 unused
(未使用)
这个状态码已经不再被使用,当初它被用HTTP 1.1规范旧版本中. HTTP/1.1 可用
307 Temporary Redirect
(临时重定向)

服务器发送该响应用来引导客户端使用相同的方法访问另外一个URI来获取想要获取的资源.新的URL会在响应的Location:头字段里找到.与302状态码有相同的语义,且前后两次访问必须使用相同的方法(GET POST).

HTTP/1.1 可用
308 Permanent Redirect
(永久重定向)

所请求的资源将永久的位于另外一个URI上.新的URL会在响应的Location:头字段里找到.与301状态码有相同的语义,且前后两次访问必须使用相同的方法(GET POST).

注意: 这是个试验性的状态码,这里是规范草案. Firefox14已经实现对该状态码的支持.

HTTPbis
(试验草案)

客户端错误
400 Bad Request
(错误请求)
因发送的请求语法错误,服务器无法正常读取. HTTP/0.9 可用
401 Unauthorized
(未授权)
需要身份验证后才能获取所请求的内容,类似于403错误.不同点是.401错误后,只要正确输入帐号密码,验证即可通过. HTTP/0.9 可用
402 Payment Required
(需要付款)
该状态被保留以供将来使用.创建此代码最初的目的是数字支付系统而用,然而,到现在也没投入使用. HTTP/0.9 and 1.1
403 Forbidden
(禁止访问)
客户端没有权利访问所请求内容,服务器拒绝本次请求. HTTP/0.9 可用
404 Not Found
(未找到)
服务器找不到所请求的资源.由于经常发生此种情况,所以该状态码在上网时是非常常见的. HTTP/0.9 可用
405 Method Not Allowed
(不允许使用该方法)
该请求使用的方法被服务器端禁止使用,RFC2616中规定, GETHEAD 方法不能被禁止. HTTP/1.1 可用
406 Not Acceptable
(无法接受)
在进行服务器驱动内容协商后,没有发现合适的内容传回给客户端. HTTP/1.1 可用
407 Proxy Authentication Required
(要求代理身份验证)

类似于状态码 401,不过需要通过代理才能进行验证.

HTTP/1.1 可用
408 Request Timeout
(请求超时)
客户端没有在服务器预备等待的时间内完成一个请求的发送.这意味着服务器将会切断和客户端的连接. 在其他浏览器中,这种响应更常见一些, 例如Chrome 和 IE9, 目的是为了使用 HTTP 预连机制 加快浏览速度 (查看{{ bug("634278") }}, Firefox在未来版本中会实现这种机制). 同时注意,一些服务器不发送此种响应就直接切断连接. HTTP/1.1 可用
409 Conflict
(冲突)
该请求与服务器的当前状态所冲突. HTTP/1.1 可用
410 Gone
(已失效)
所请求的资源已经被删除. HTTP/1.1 可用
411 Length Required
(需要内容长度头)
因服务器在本次请求中需要 Content-Length 头字段,而客户端没有发送.所以,服务器拒绝了该请求. HTTP/1.1 可用
412 Precondition Failed
(预处理失败)
服务器没能满足客户端在获取资源时在请求头字段中设置的先决条件. HTTP/1.1 可用
413 Request Entity Too Large
(请求实体过长)
请求实体大小超过服务器的设置的最大限制,服务器可能会关闭HTTP链接并返回Retry-After 头字段. HTTP/1.1 可用
414 Request-URI Too Long
(请求网址过长)
客户端请求所包含的URI地址太长,以至于服务器无法处理. HTTP/1.1 可用
415 Unsupported Media Type
(媒体类型不支持)
服务器不支持客户端所请求的媒体类型,因此拒绝该请求. HTTP/1.1 可用
416 Requested Range Not Satisfiable
(请求范围不合要求)
请求中包含的Range头字段无法被满足,通常是因为Range中的数字范围超出所请求资源的大小. HTTP/1.1 可用
417 Expectation Failed
(预期结果失败)
在请求头 Expect 中指定的预期内容无法被服务器满足. HTTP/1.1 可用
服务器端错误
500 Internal Server Error
(内部服务器错误)
服务器遇到未知的无法解决的问题. HTTP/0.9 可用
501 Implemented
(未实现)
服务器不支持该请求中使用的方法,比如POSTPUT.只有GETHEAD 是RFC2616规范中规定服务器必须实现的方法. HTTP/0.9 可用
502 Bad Gateway
(网关错误)
服务器作为网关且从上游服务器获取到了一个无效的HTTP响应. HTTP/0.9 可用
503 Service Unavailable
(服务不可用)
由于临时的服务器维护或者过载,服务器当前无法处理请求.这个状况是临时的,并且将在一段时间以后恢复.如果能够预计延迟时间,那么响应中可以包含一个Retry-After:头用以标明这个延迟时间.如果没有给出这个Retry-After:信息,那么客户端应当以处理500响应的方式处理它.同时,这种情况下,一个友好的用于解释服务器出现问题的页面应当被返回,并且,缓存相关的HTTP头信息也应该包含,因为通常这种错误提示网页不应当被客户端缓存. HTTP/0.9 可用
504 Gateway Timeout 
(网关超时)
服务器作为网关且不能从上游服务器及时的得到响应返回给客户端. HTTP/1.1 可用
505 HTTP Version Not Supported
(HTTP版本不受支持)
服务器不支持客户端发送的HTTP请求中所使用的HTTP协议版本. HTTP/1.1 可用 
-

 

-

{{ languages( { "en": "en/HTTP/HTTP_response_codes"} ) }}

diff --git a/files/zh-cn/web/http/http_strict_transport_security/index.html b/files/zh-cn/web/http/http_strict_transport_security/index.html deleted file mode 100644 index d890b429ef..0000000000 --- a/files/zh-cn/web/http/http_strict_transport_security/index.html +++ /dev/null @@ -1,121 +0,0 @@ ---- -title: HTTP Strict Transport Security -slug: Web/HTTP/HTTP_Strict_Transport_Security -tags: - - HSTS - - HTTP - - HTTPS - - Security - - header -translation_of: Web/HTTP/Headers/Strict-Transport-Security ---- -
 HTTP Strict Transport Security(通常简称为{{Glossary("HSTS")}})是一个安全功能,它告诉浏览器只能通过HTTPS访问当前资源,而不是HTTP
- - - - - - - - - - - - -
Header type{{Glossary("Response header")}}
{{Glossary("Forbidden header name")}}no
- -

语法

- -
Strict-Transport-Security: max-age=<expire-time>
-Strict-Transport-Security: max-age=<expire-time>; includeSubDomains
-Strict-Transport-Security: max-age=<expire-time>; preload
-
- -

指令

- -
-
max-age=<expire-time>
-
设置在浏览器收到这个请求后的<expire-time>秒的时间内凡是访问这个域名下的请求都使用HTTPS请求。
-
includeSubDomains {{optional_inline}}
-
如果这个可选的参数被指定,那么说明此规则也适用于该网站的所有子域名。
-
preload {{optional_inline}}
-
查看 {{anch("预加载 HSTS")}} 获得详情。不是标准的一部分。
-
- -

描述

- -

一个网站接受一个HTTP的请求,然后跳转到HTTPS,用户可能在开始跳转前,通过没有加密的方式和服务器对话,比如,用户输入http://foo.com或者直接foo.com。

- -

这样存在中间人攻击潜在威胁,跳转过程可能被恶意网站利用来直接接触用户信息,而不是原来的加密信息。

- -

网站通过HTTP Strict Transport Security通知浏览器,这个网站禁止使用HTTP方式加载,浏览器应该自动把所有尝试使用HTTP的请求自动替换为HTTPS请求。

- -
-

注意: Strict-Transport-Security 在通过 HTTP 访问时会被浏览器忽略; 因为攻击者可以通过中间人攻击的方式在连接中修改、注入或删除它.  只有在你的网站通过HTTPS访问并且没有证书错误时, 浏览器才认为你的网站支持HTTPS 然后使用 Strict-Transport-Security 的值 .

-
- -

浏览器如何处理

- -

你的网站第一次通过HTTPS请求,服务器响应Strict-Transport-Security 头,浏览器记录下这些信息,然后后面尝试访问这个网站的请求都会自动把HTTP替换为HTTPS。

- -

当HSTS头设置的过期时间到了,后面通过HTTP的访问恢复到正常模式,不会再自动跳转到HTTPS。

- -

每次浏览器接收到Strict-Transport-Security头,它都会更新这个网站的过期时间,所以网站可以刷新这些信息,防止过期发生。

- -

Chrome、Firefox等浏览器里,当您尝试访问该域名下的内容时,会产生一个307 Internal Redirect(内部跳转),自动跳转到HTTPS请求。

- -

示例场景

- -

你连接到一个免费WiFi接入点,然后开始浏览网站,访问你的网上银行,查看你的支出,并且支付一些订单。很不幸,你接入的WiFi实际上是黑客的笔记本热点,他们拦截了你最初的HTTP请求,然后跳转到一个你银行网站一模一样的钓鱼网站。 现在,你的隐私数据暴露给黑客了。

- -

Strict Transport Security解决了这个问题;只要你通过HTTPS请求访问银行网站,并且银行网站配置好Strict Transport Security,你的浏览器知道自动使用HTTPS请求,这可以阻止黑客的中间人攻击的把戏。

- -

预加载 HSTS

- -

谷歌维护着一个 HSTS 预加载服务。按照如下指示成功提交你的域名后,浏览器将会永不使用非安全的方式连接到你的域名。虽然该服务是由谷歌提供的,但所有浏览器都有使用这份列表的意向(或者已经在用了)。但是,这不是 HSTS 标准的一部分,也不该被当作正式的内容。

- - - -

示例

- -

现在和未来的所有子域名会自动使用 HTTPS 连接长达一年。同时阻止了只能通过 HTTP 访问的内容。

- -
Strict-Transport-Security: max-age=31536000; includeSubDomains
-
- -

规范

- - - - - - - - - - - - - - -
规范状态注释
{{SpecName('HSTS')}}{{Spec2('HSTS')}}Initial definition
- -

浏览器兼容

- - - -

{{Compat("http.headers.Strict-Transport-Security")}}

- -

查看更多

- - diff --git a/files/zh-cn/web/http/proxy_servers_and_tunneling/proxy_auto-configuration_(pac)_file/index.html b/files/zh-cn/web/http/proxy_servers_and_tunneling/proxy_auto-configuration_(pac)_file/index.html deleted file mode 100644 index e64b1758ff..0000000000 --- a/files/zh-cn/web/http/proxy_servers_and_tunneling/proxy_auto-configuration_(pac)_file/index.html +++ /dev/null @@ -1,729 +0,0 @@ ---- -title: 代理自动配置文件(PAC)文件 -slug: Web/HTTP/Proxy_servers_and_tunneling/Proxy_Auto-Configuration_(PAC)_file -translation_of: Web/HTTP/Proxy_servers_and_tunneling/Proxy_Auto-Configuration_(PAC)_file ---- -
{{HTTPSidebar}}
- -

代理自动配置(PAC)文件是一个 JavaScript 脚本,其核心是一个 JavaScript 函数,用来决定网页浏览请求(HTTP、HTTPS,和 FTP)应当直连目标地址,还是被转发给一个网页代理服务器并通过代理连接。PAC 文件中的核心 JavaScript 函数通常是这样定义的:

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

语法

- -
function FindProxyForURL(url, host)
- -

参数

- -
-
url
-
要访问的 URL。URL 中类似 https:// 这样的的路径和查询组件已被去除。在 Chrome 浏览器(版本 52 至 73)中, 你可以通过设置 PacHttpsUrlStrippingEnabledfalse 来禁止这种行为,或者以 --unsafe-pac-url 命令行参数启动(自 Chrome 74 起,仅命令行参数有效,且在 Chrome 75 及之后的版本中无法禁用这种行为;至于 Chrome 81,路径剥离对 HTTP URL 不适用,但有意改变这一行为以适应 HTTPS);在 Firefox 浏览器中,对应的选项是 network.proxy.autoconfig_url.include_path
-
host
-
从 URL 中提取得到的主机名。这只是为了方便;它与 :// 之后到第一个 :/ 之前的字符串相同。端口号不包括在此参数中,必要时可以自行从 URL 中提取。
-
- -

描述

- -

返回一个描述了代理设置的字符串。字符串的格式按照返回值格式进行定义。

- -

返回值格式

- - - -
-
DIRECT
-
直连,不经过任何代理
-
PROXY host:port
-
HTTP 代理
-
SOCKS host:port
-
SOCKS 代理
-
- -

最近版本的 Firefox 同时还支持:

- -
-
HTTP host:port
-
HTTP 代理
-
HTTPS host:port
-
HTTPS 代理
-
SOCKS4 host:port
-
SOCKS5 host:port
-
SOCKS 代理(同时指定 SOCKS 版本)
-
- -

如果有多个使用分号分隔的代理配置,将使用最左边的配置,除非 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; DIRECT
-
和上面的基本一样,但如果两个代理都挂了,则自动改为直连。(在上面的例子中,Netscape 浏览器将询问用户是否要改用直接连接;在本例中,则不需要用户干预。)
-
PROXY w3proxy.netscape.com:8080; SOCKS socks:1080
-
如果主代理出现问题,则使用 SOCKS 连接。
-
- -

自动配置文件应当被保存为一个以 .pac 作为文件拓展名的文件,比如:

- -
proxy.pac
- -

其 MIME 类型应被设置为:

- -
application/x-ns-proxy-autoconfig
- -

接下来,你应当配置你的服务器,让文件拓展名 .pac 映射到如上所示的 MIME 类型。

- -
-

注意:

- - -
- -

预定义的函数与环境

- -

这些函数可以在 PAC 文件中使用:

- - - -
-

注意: pactester ( pacparser 的一部分) 可以用来检测语法是否符合要求,使用方法如下:

- - -
- -

isPlainHostName()

- -

语法

- -
isPlainHostName(host)
- -

参数

- -
-
host
-
从 URL 中得到的主机名(端口除外)。
-
- -

描述

- -

当且仅当主机名中没有域名时为真(没有分隔域名的点)。

- -

例子

- -
isPlainHostName("www.mozilla.org") // false
-isPlainHostName("www") // true
-
- -

dnsDomainIs()

- -

语法

- -
dnsDomainIs(host, domain)
- -

参数

- -
-
host
-
从 URL 中得到的主机名。
-
domain
-
域名/部分域名
-
- -

描述

- -

如果匹配,返回true。

- -

例子

- -
dnsDomainIs("www.mozilla.org", ".mozilla.org") // true
-dnsDomainIs("www", ".mozilla.org") // false
-
- -

localHostOrDomainIs()

- -

语法

- -
localHostOrDomainIs(host, hostdom)
- -

参数

- -
-
host
-
从 URL 中得到的主机名。
-
hostdom
-
完整域名
-
- -

描述

- -

完整域名匹配或主机名(如www)匹配时返回true。

- -

例子

- -
localHostOrDomainIs("www.mozilla.org" , "www.mozilla.org") // true (exact match)
-localHostOrDomainIs("www"             , "www.mozilla.org") // true (hostname match, domain not specified)
-localHostOrDomainIs("www.google.com"  , "www.mozilla.org") // false (domain name mismatch)
-localHostOrDomainIs("home.mozilla.org", "www.mozilla.org") // false (hostname mismatch)
- -

isResolvable()

- -

语法

- -
isResolvable(host)
- -

参数

- -
-
host
-
从 URL 中得到的主机名。
-
- -

尝试解析主机名。如果成功,则返回true。

- -

例子:

- -
isResolvable("www.mozilla.org") // true
-
- -

isInNet()

- -

语法

- -
isInNet(host, pattern, mask)
- -

参数

- -
-
host
-
一个 DNS 主机名,或者一个 IP 地址。如果传入了主机名,则会被此函数解析为 IP 地址,再进行判断。
-
pattern
-
点号(.)分隔的IP地址。
-
mask
-
子网掩码,0 代表忽略,255 代表完全匹配。
-
- -

仅在 host 属于由 pattern 和 mask 指定的ip地址段时返回true。

- -

Pattern and mask specification is done the same way as for SOCKS configuration.

- -

例子:

- -
function alert_eval(str) { alert(str + ' is ' + eval(str)) }
-function FindProxyForURL(url, host) {
-  alert_eval('isInNet(host, "63.245.213.24", "255.255.255.255")')
-  // "PAC-alert: isInNet(host, "63.245.213.24", "255.255.255.255") is true"
-}
-
- -

dnsResolve()

- -
dnsResolve(host)
- -

参数

- -
-
host
-
要解析的主机名。
-
- -

将给定的 DNS 主机名解析为 IP 地址并返回为标准格式的 IP 地址字符串。

- -

例子

- -
dnsResolve("www.mozilla.org"); // returns the string "104.16.41.2"
- -

convert_addr()

- -

语法

- -
convert_addr(ipaddr)
- -

参数

- -
-
ipaddr
-
点号(.)分隔的IP地址或子网掩码。
-
- -

将IP地址转换为32位整数地址。

- -

例子

- -
convert_addr("104.16.41.2"); // returns the decimal number 1745889538
- -

myIpAddress()

- -

语法

- -
myIpAddress()
- -

参数

- -

(无)

- -

获取当前 Firefox 所在设备的 IP 地址,并返回为标准格式的 IP 地址字符串。

- -
-

myIpAddress() 返回与 nslookup localhost 命令在 Linux 主机上的执行结果相同的 IP 地址。不会返回公网 IP 地址。

-
- -

例子

- -
myIpAddress() //returns the string "127.0.1.1" if you were running Firefox on that localhost
- -

dnsDomainLevels()

- -

语法

- -
dnsDomainLevels(host)
- -

参数

- -
-
host
-
从 URL 中得到的主机名。
-
- -

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

- -

例子:

- -
dnsDomainLevels("www");             // 0
-dnsDomainLevels("mozilla.org");     // 1
-dnsDomainLevels("www.mozilla.org"); // 2
-
- -

shExpMatch()

- -

语法

- -
shExpMatch(str, shexp)
- -

参数

- -
-
str
-
任何要比较的字符串(如URL或主机名)。
-
shexp
-
要用来对比的 Shell 表达式。
-
- -

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

- -

注意,本函数接收 shell glob 表达式而非正则表达式。*? 始终被支持,[characters][^characters] 只在包括 Firefox 在内的某些实现上被支持。这主要是由于 glob 表达式在内部被翻译为正则表达式。如要使用正则表达式语法,请直接使用 RegExp 类。

- -

例子

- -
shExpMatch("http://home.netscape.com/people/ari/index.html"     , "*/ari/*"); // returns true
-shExpMatch("http://home.netscape.com/people/montulli/index.html", "*/ari/*"); // returns false
- -

weekdayRange()

- -

语法

- -
weekdayRange(wd1, wd2, [gmt])
- -
-

注意: (Before Firefox 49) wd1 must be less than wd2 if you want the function to evaluate these parameters as a range. See the warning below.

-
- -

参数

- -
-
wd1 和 wd2
-
One of the ordered weekday strings:
-
-
"SUN"|"MON"|"TUE"|"WED"|"THU"|"FRI"|"SAT"
-
-
gmt
-
可以指定为字符串 "GMT",或留白不指定。
-
- -

Only the first parameter is mandatory. Either the second, the third, or both may be left out.

- -

If only one parameter is present, the function returns a value of true on the weekday that the parameter represents. If the string "GMT" is specified as a second parameter, times are taken to be in GMT. Otherwise, they are assumed to be in the local timezone.

- -

If both wd1 and wd1 are defined, the condition is true if the current weekday is in between those two ordered weekdays. Bounds are inclusive, but the bounds are ordered. 如果指定了 "GMT" 参数,则使用 GMT 时区,否则使用浏览器获取到的平台本地时区。

- -
-

The order of the days matters; Before Firefox 49, weekdayRange("SUN", "SAT") will always evaluate to true. Now weekdayRange("WED", "SUN") will only evaluate true if the current day is Wednesday or Sunday.

-
- -

例子

- -
weekdayRange("MON", "FRI");        // returns true Monday through Friday (local timezone)
-weekdayRange("MON", "FRI", "GMT"); // returns true Monday through Friday (GMT timezone)
-weekdayRange("SAT");               // returns true on Saturdays local time
-weekdayRange("SAT", "GMT");        // returns true on Saturdays GMT time
-weekdayRange("FRI", "MON");        // returns true Friday and Monday only (note, order does matter!)
- -

dateRange()

- -

语法

- -
dateRange(<day> | <month> | <year>, [gmt])  // ambiguity is resolved by assuming year is greater than 31
-dateRange(<day1>, <day2>, [gmt])
-dateRange(<month1>, <month2>, [gmt])
-dateRange(<year1>, <year2>, [gmt])
-dateRange(<day1>, <month1>, <day2>, <month2>, [gmt])
-dateRange(<month1>, <year1>, <month2>, <year2>, [gmt])
-dateRange(<day1>, <month1>, <year1>, <day2>, <month2>, <year2>, [gmt])
- -
-

注意: (Before Firefox 49) day1 must be less than day2, month1 must be less than month2, and year1 must be less than year2 if you want the function to evaluate these parameters as a range. See the warning below.

-
- -

参数

- -
-
day
-
Is the ordered day of the month between 1 and 31 (as an integer).
-
- -
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
- -
-
month
-
Is one of the ordered month strings below.
-
- -
"JAN"|"FEB"|"MAR"|"APR"|"MAY"|"JUN"|"JUL"|"AUG"|"SEP"|"OCT"|"NOV"|"DEC"
- -
-
year
-
Is the ordered full year integer number. For example, 2016 (not 16).
-
gmt
-
可以指定为字符串 "GMT",代表使用 GMT 时区进行比较;或者留白不指定,代表使用浏览器获取到的平台本地时区。
-
- -

If only a single value is specified (from each category: day, month, year), the function returns a true value only on days that match that specification. If both values are specified, the result is true between those times, including bounds, but the bounds are ordered.

- -
-

The order of the days, months, and years matter; Before Firefox 49, dateRange("JAN", "DEC") will always evaluate to true. Now dateRange("DEC", "JAN") will only evaluate true if the current month is December or January.

-
- -

例子

- -
dateRange(1);            // returns true on the first day of each month, local timezone
-dateRange(1, "GMT")      // returns true on the first day of each month, GMT timezone
-dateRange(1, 15);        // returns true on the first half of each month
-dateRange(24, "DEC");    // returns true on 24th of December each year
-dateRange("JAN", "MAR"); // returns true on the first quarter of the year
-
-dateRange(1, "JUN", 15, "AUG");
-// returns true from June 1st until August 15th, each year
-// (including June 1st and August 15th)
-
-dateRange(1, "JUN", 1995, 15, "AUG", 1995);
-// returns true from June 1st, 1995, until August 15th, same year
-
-dateRange("OCT", 1995, "MAR", 1996);
-// returns true from October 1995 until March 1996
-// (including the entire month of October 1995 and March 1996)
-
-dateRange(1995);
-// returns true during the entire year of 1995
-
-dateRange(1995, 1997);
-// returns true from beginning of year 1995 until the end of year 1997
- -

timeRange()

- -

语法

- -
// The full range of expansions is analogous to dateRange.
-timeRange(<hour1>, <min1>, <sec1>, <hour2>, <min2>, <sec2>, [gmt])
- -
-

注意: (Before Firefox 49) the category hour1, min1, sec1 must be less than the category hour2, min2, sec2 if you want the function to evaluate these parameters as a range. See the warning below.

-
- -

参数

- -
-
hour
-
小时,区间为 0 到 23。(0 是午夜 0 点,1 是上午 1 点,11 是正午 12 点,23 是下午 11 点。)
-
min
-
分钟,区间为 0 到 59。
-
sec
-
 秒,区间为 0 到 59。
-
gmt
-
可以指定为字符串 "GMT",代表使用 GMT 时区,或者留白不指定,代表使用浏览器获取到的平台本地时区。
-
- -

If only a single value is specified (from each category: hour, minute, second), the function returns a true value only at times that match that specification. If both values are specified, the result is true between those times, including bounds, but the bounds are ordered.

- -
-

The order of the hour, minute, second matter; Before Firefox 49, timeRange(0, 23) will always evaluate to true. Now timeRange(23, 0) will only evaluate true if the current hour is 23:00 or midnight.

-
- -

例子

- -
timerange(12);                // returns true from noon to 1pm
-timerange(12, 13);            // returns true from noon to 1pm
-timerange(12, "GMT");         // returns true from noon to 1pm, in GMT timezone
-timerange(9, 17);             // returns true from 9am to 5pm
-timerange(8, 30, 17, 00);     // returns true from 8:30am to 5:00pm
-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";
-  }
-}
- -
-

注意: 这是只有一个代理服务器情况下最简单高效的自动配置脚本。

-
- -

例 2

- -

和例 1 一样,但是对防火墙外的本地服务器使用代理

- -

如果有主机(例如生产环境中的 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.orgmerchant.mozilla.org 也使用代理。

- -
-

注意:以上例外的顺序影响效率:localHostOrDomainIs() 只在 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

- -

基于网域(Subnet)的选择方案

- -

在此示例中,所有同一子网内的主机均直接连接,其他主机则通过代理连接:

- -
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 模式(pattern)的路由规划

- -

This example is more sophisticated. There are four (4) proxy servers; one of them is a hot stand-by for all of the other ones, so if any of the remaining three goes down the fourth one will take over. Furthermore, the three remaining proxy servers share the load based on URL patterns, which makes their caching more effective (there is only one copy of any document on the three servers - as opposed to one copy on each of them). The load is distributed like this:

- - - - - - - - - - - - - - - - - - - - - - - - -
代理用途
#1.com 域名
#2.edu 域名
#3所有其他域名
#4备用(原文:hot stand-by,活跃备用、热备用)
- -

All local accesses are desired to be direct. All proxy servers run on the port 8080 (they don't need to, you can just change your port but remember to modify your configuations on both side). Note how strings can be concatenated with the + operator in 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() 中可用。作为例子,我们通过{{jsxref("String.prototype.startsWith()", "startsWith()")}} 为不同的协议设置不同的代理。

- -
function FindProxyForURL(url, host) {
-
-  if (url.startsWith("http:"))
-    return "PROXY http-proxy.mydomain.com:8080";
-
-  else if (url.startsWith("ftp:"))
-    return "PROXY ftp-proxy.mydomain.com:8080";
-
-  else if (url.startsWith(“gopher:"))
-    return "PROXY gopher-proxy.mydomain.com:8080";
-
-  else if (url.startsWith("https:") || url.startsWith("snews:"))
-    return "PROXY security-proxy.mydomain.com:8080";
-
-  else
-    return "DIRECT";
-
-}
- -
-

注意: shExpMatch() 也可以做到,例如:

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

自动配置脚本也可以在服务端动态生成。这在某些情况下比较有用,例如根据客户端地址指定不同的代理服务器。

- -

isInNet()isResolvable()dnsResolve() 应该谨慎使用,这些函数会进行  DNS 查询。其他函数则大都是字符处理函数,不需要 DNS 。如果通过代理连接,代理本身也会进行一次 DNS 查询,这产生了额外的 DNS 请求。并且绝大多数情况下,不需要这些函数来实现特定的功能。

-
- -

历史与实现

- -

Proxy auto-config was introduced into Netscape Navigator 2.0 in the late 1990s, at the same time when JavaScript was introduced. Open-sourcing Netscape eventually lead to Firefox itself.

- -

The most "original" implementation of PAC and its JavaScript libraries is, therefore, nsProxyAutoConfig.js found in early versions of Firefox. These utilities are found in many other open-source systems including Chromium. Firefox later integrated the file into ProxyAutoConfig.cpp as a string literal.

- -

Microsoft in general made its own implementation. There used to be some problems with their libraries, but most are resolved by now. They have defined some new "Ex" suffixed functions around the address handling parts to support IPv6. The feature is supported by Chromium, but not yet by Firefox (bugzilla #558253).

diff --git a/files/zh-cn/web/http/proxy_servers_and_tunneling/proxy_auto-configuration_pac_file/index.html b/files/zh-cn/web/http/proxy_servers_and_tunneling/proxy_auto-configuration_pac_file/index.html new file mode 100644 index 0000000000..e64b1758ff --- /dev/null +++ b/files/zh-cn/web/http/proxy_servers_and_tunneling/proxy_auto-configuration_pac_file/index.html @@ -0,0 +1,729 @@ +--- +title: 代理自动配置文件(PAC)文件 +slug: Web/HTTP/Proxy_servers_and_tunneling/Proxy_Auto-Configuration_(PAC)_file +translation_of: Web/HTTP/Proxy_servers_and_tunneling/Proxy_Auto-Configuration_(PAC)_file +--- +
{{HTTPSidebar}}
+ +

代理自动配置(PAC)文件是一个 JavaScript 脚本,其核心是一个 JavaScript 函数,用来决定网页浏览请求(HTTP、HTTPS,和 FTP)应当直连目标地址,还是被转发给一个网页代理服务器并通过代理连接。PAC 文件中的核心 JavaScript 函数通常是这样定义的:

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

语法

+ +
function FindProxyForURL(url, host)
+ +

参数

+ +
+
url
+
要访问的 URL。URL 中类似 https:// 这样的的路径和查询组件已被去除。在 Chrome 浏览器(版本 52 至 73)中, 你可以通过设置 PacHttpsUrlStrippingEnabledfalse 来禁止这种行为,或者以 --unsafe-pac-url 命令行参数启动(自 Chrome 74 起,仅命令行参数有效,且在 Chrome 75 及之后的版本中无法禁用这种行为;至于 Chrome 81,路径剥离对 HTTP URL 不适用,但有意改变这一行为以适应 HTTPS);在 Firefox 浏览器中,对应的选项是 network.proxy.autoconfig_url.include_path
+
host
+
从 URL 中提取得到的主机名。这只是为了方便;它与 :// 之后到第一个 :/ 之前的字符串相同。端口号不包括在此参数中,必要时可以自行从 URL 中提取。
+
+ +

描述

+ +

返回一个描述了代理设置的字符串。字符串的格式按照返回值格式进行定义。

+ +

返回值格式

+ + + +
+
DIRECT
+
直连,不经过任何代理
+
PROXY host:port
+
HTTP 代理
+
SOCKS host:port
+
SOCKS 代理
+
+ +

最近版本的 Firefox 同时还支持:

+ +
+
HTTP host:port
+
HTTP 代理
+
HTTPS host:port
+
HTTPS 代理
+
SOCKS4 host:port
+
SOCKS5 host:port
+
SOCKS 代理(同时指定 SOCKS 版本)
+
+ +

如果有多个使用分号分隔的代理配置,将使用最左边的配置,除非 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; DIRECT
+
和上面的基本一样,但如果两个代理都挂了,则自动改为直连。(在上面的例子中,Netscape 浏览器将询问用户是否要改用直接连接;在本例中,则不需要用户干预。)
+
PROXY w3proxy.netscape.com:8080; SOCKS socks:1080
+
如果主代理出现问题,则使用 SOCKS 连接。
+
+ +

自动配置文件应当被保存为一个以 .pac 作为文件拓展名的文件,比如:

+ +
proxy.pac
+ +

其 MIME 类型应被设置为:

+ +
application/x-ns-proxy-autoconfig
+ +

接下来,你应当配置你的服务器,让文件拓展名 .pac 映射到如上所示的 MIME 类型。

+ +
+

注意:

+ + +
+ +

预定义的函数与环境

+ +

这些函数可以在 PAC 文件中使用:

+ + + +
+

注意: pactester ( pacparser 的一部分) 可以用来检测语法是否符合要求,使用方法如下:

+ + +
+ +

isPlainHostName()

+ +

语法

+ +
isPlainHostName(host)
+ +

参数

+ +
+
host
+
从 URL 中得到的主机名(端口除外)。
+
+ +

描述

+ +

当且仅当主机名中没有域名时为真(没有分隔域名的点)。

+ +

例子

+ +
isPlainHostName("www.mozilla.org") // false
+isPlainHostName("www") // true
+
+ +

dnsDomainIs()

+ +

语法

+ +
dnsDomainIs(host, domain)
+ +

参数

+ +
+
host
+
从 URL 中得到的主机名。
+
domain
+
域名/部分域名
+
+ +

描述

+ +

如果匹配,返回true。

+ +

例子

+ +
dnsDomainIs("www.mozilla.org", ".mozilla.org") // true
+dnsDomainIs("www", ".mozilla.org") // false
+
+ +

localHostOrDomainIs()

+ +

语法

+ +
localHostOrDomainIs(host, hostdom)
+ +

参数

+ +
+
host
+
从 URL 中得到的主机名。
+
hostdom
+
完整域名
+
+ +

描述

+ +

完整域名匹配或主机名(如www)匹配时返回true。

+ +

例子

+ +
localHostOrDomainIs("www.mozilla.org" , "www.mozilla.org") // true (exact match)
+localHostOrDomainIs("www"             , "www.mozilla.org") // true (hostname match, domain not specified)
+localHostOrDomainIs("www.google.com"  , "www.mozilla.org") // false (domain name mismatch)
+localHostOrDomainIs("home.mozilla.org", "www.mozilla.org") // false (hostname mismatch)
+ +

isResolvable()

+ +

语法

+ +
isResolvable(host)
+ +

参数

+ +
+
host
+
从 URL 中得到的主机名。
+
+ +

尝试解析主机名。如果成功,则返回true。

+ +

例子:

+ +
isResolvable("www.mozilla.org") // true
+
+ +

isInNet()

+ +

语法

+ +
isInNet(host, pattern, mask)
+ +

参数

+ +
+
host
+
一个 DNS 主机名,或者一个 IP 地址。如果传入了主机名,则会被此函数解析为 IP 地址,再进行判断。
+
pattern
+
点号(.)分隔的IP地址。
+
mask
+
子网掩码,0 代表忽略,255 代表完全匹配。
+
+ +

仅在 host 属于由 pattern 和 mask 指定的ip地址段时返回true。

+ +

Pattern and mask specification is done the same way as for SOCKS configuration.

+ +

例子:

+ +
function alert_eval(str) { alert(str + ' is ' + eval(str)) }
+function FindProxyForURL(url, host) {
+  alert_eval('isInNet(host, "63.245.213.24", "255.255.255.255")')
+  // "PAC-alert: isInNet(host, "63.245.213.24", "255.255.255.255") is true"
+}
+
+ +

dnsResolve()

+ +
dnsResolve(host)
+ +

参数

+ +
+
host
+
要解析的主机名。
+
+ +

将给定的 DNS 主机名解析为 IP 地址并返回为标准格式的 IP 地址字符串。

+ +

例子

+ +
dnsResolve("www.mozilla.org"); // returns the string "104.16.41.2"
+ +

convert_addr()

+ +

语法

+ +
convert_addr(ipaddr)
+ +

参数

+ +
+
ipaddr
+
点号(.)分隔的IP地址或子网掩码。
+
+ +

将IP地址转换为32位整数地址。

+ +

例子

+ +
convert_addr("104.16.41.2"); // returns the decimal number 1745889538
+ +

myIpAddress()

+ +

语法

+ +
myIpAddress()
+ +

参数

+ +

(无)

+ +

获取当前 Firefox 所在设备的 IP 地址,并返回为标准格式的 IP 地址字符串。

+ +
+

myIpAddress() 返回与 nslookup localhost 命令在 Linux 主机上的执行结果相同的 IP 地址。不会返回公网 IP 地址。

+
+ +

例子

+ +
myIpAddress() //returns the string "127.0.1.1" if you were running Firefox on that localhost
+ +

dnsDomainLevels()

+ +

语法

+ +
dnsDomainLevels(host)
+ +

参数

+ +
+
host
+
从 URL 中得到的主机名。
+
+ +

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

+ +

例子:

+ +
dnsDomainLevels("www");             // 0
+dnsDomainLevels("mozilla.org");     // 1
+dnsDomainLevels("www.mozilla.org"); // 2
+
+ +

shExpMatch()

+ +

语法

+ +
shExpMatch(str, shexp)
+ +

参数

+ +
+
str
+
任何要比较的字符串(如URL或主机名)。
+
shexp
+
要用来对比的 Shell 表达式。
+
+ +

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

+ +

注意,本函数接收 shell glob 表达式而非正则表达式。*? 始终被支持,[characters][^characters] 只在包括 Firefox 在内的某些实现上被支持。这主要是由于 glob 表达式在内部被翻译为正则表达式。如要使用正则表达式语法,请直接使用 RegExp 类。

+ +

例子

+ +
shExpMatch("http://home.netscape.com/people/ari/index.html"     , "*/ari/*"); // returns true
+shExpMatch("http://home.netscape.com/people/montulli/index.html", "*/ari/*"); // returns false
+ +

weekdayRange()

+ +

语法

+ +
weekdayRange(wd1, wd2, [gmt])
+ +
+

注意: (Before Firefox 49) wd1 must be less than wd2 if you want the function to evaluate these parameters as a range. See the warning below.

+
+ +

参数

+ +
+
wd1 和 wd2
+
One of the ordered weekday strings:
+
+
"SUN"|"MON"|"TUE"|"WED"|"THU"|"FRI"|"SAT"
+
+
gmt
+
可以指定为字符串 "GMT",或留白不指定。
+
+ +

Only the first parameter is mandatory. Either the second, the third, or both may be left out.

+ +

If only one parameter is present, the function returns a value of true on the weekday that the parameter represents. If the string "GMT" is specified as a second parameter, times are taken to be in GMT. Otherwise, they are assumed to be in the local timezone.

+ +

If both wd1 and wd1 are defined, the condition is true if the current weekday is in between those two ordered weekdays. Bounds are inclusive, but the bounds are ordered. 如果指定了 "GMT" 参数,则使用 GMT 时区,否则使用浏览器获取到的平台本地时区。

+ +
+

The order of the days matters; Before Firefox 49, weekdayRange("SUN", "SAT") will always evaluate to true. Now weekdayRange("WED", "SUN") will only evaluate true if the current day is Wednesday or Sunday.

+
+ +

例子

+ +
weekdayRange("MON", "FRI");        // returns true Monday through Friday (local timezone)
+weekdayRange("MON", "FRI", "GMT"); // returns true Monday through Friday (GMT timezone)
+weekdayRange("SAT");               // returns true on Saturdays local time
+weekdayRange("SAT", "GMT");        // returns true on Saturdays GMT time
+weekdayRange("FRI", "MON");        // returns true Friday and Monday only (note, order does matter!)
+ +

dateRange()

+ +

语法

+ +
dateRange(<day> | <month> | <year>, [gmt])  // ambiguity is resolved by assuming year is greater than 31
+dateRange(<day1>, <day2>, [gmt])
+dateRange(<month1>, <month2>, [gmt])
+dateRange(<year1>, <year2>, [gmt])
+dateRange(<day1>, <month1>, <day2>, <month2>, [gmt])
+dateRange(<month1>, <year1>, <month2>, <year2>, [gmt])
+dateRange(<day1>, <month1>, <year1>, <day2>, <month2>, <year2>, [gmt])
+ +
+

注意: (Before Firefox 49) day1 must be less than day2, month1 must be less than month2, and year1 must be less than year2 if you want the function to evaluate these parameters as a range. See the warning below.

+
+ +

参数

+ +
+
day
+
Is the ordered day of the month between 1 and 31 (as an integer).
+
+ +
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
+ +
+
month
+
Is one of the ordered month strings below.
+
+ +
"JAN"|"FEB"|"MAR"|"APR"|"MAY"|"JUN"|"JUL"|"AUG"|"SEP"|"OCT"|"NOV"|"DEC"
+ +
+
year
+
Is the ordered full year integer number. For example, 2016 (not 16).
+
gmt
+
可以指定为字符串 "GMT",代表使用 GMT 时区进行比较;或者留白不指定,代表使用浏览器获取到的平台本地时区。
+
+ +

If only a single value is specified (from each category: day, month, year), the function returns a true value only on days that match that specification. If both values are specified, the result is true between those times, including bounds, but the bounds are ordered.

+ +
+

The order of the days, months, and years matter; Before Firefox 49, dateRange("JAN", "DEC") will always evaluate to true. Now dateRange("DEC", "JAN") will only evaluate true if the current month is December or January.

+
+ +

例子

+ +
dateRange(1);            // returns true on the first day of each month, local timezone
+dateRange(1, "GMT")      // returns true on the first day of each month, GMT timezone
+dateRange(1, 15);        // returns true on the first half of each month
+dateRange(24, "DEC");    // returns true on 24th of December each year
+dateRange("JAN", "MAR"); // returns true on the first quarter of the year
+
+dateRange(1, "JUN", 15, "AUG");
+// returns true from June 1st until August 15th, each year
+// (including June 1st and August 15th)
+
+dateRange(1, "JUN", 1995, 15, "AUG", 1995);
+// returns true from June 1st, 1995, until August 15th, same year
+
+dateRange("OCT", 1995, "MAR", 1996);
+// returns true from October 1995 until March 1996
+// (including the entire month of October 1995 and March 1996)
+
+dateRange(1995);
+// returns true during the entire year of 1995
+
+dateRange(1995, 1997);
+// returns true from beginning of year 1995 until the end of year 1997
+ +

timeRange()

+ +

语法

+ +
// The full range of expansions is analogous to dateRange.
+timeRange(<hour1>, <min1>, <sec1>, <hour2>, <min2>, <sec2>, [gmt])
+ +
+

注意: (Before Firefox 49) the category hour1, min1, sec1 must be less than the category hour2, min2, sec2 if you want the function to evaluate these parameters as a range. See the warning below.

+
+ +

参数

+ +
+
hour
+
小时,区间为 0 到 23。(0 是午夜 0 点,1 是上午 1 点,11 是正午 12 点,23 是下午 11 点。)
+
min
+
分钟,区间为 0 到 59。
+
sec
+
 秒,区间为 0 到 59。
+
gmt
+
可以指定为字符串 "GMT",代表使用 GMT 时区,或者留白不指定,代表使用浏览器获取到的平台本地时区。
+
+ +

If only a single value is specified (from each category: hour, minute, second), the function returns a true value only at times that match that specification. If both values are specified, the result is true between those times, including bounds, but the bounds are ordered.

+ +
+

The order of the hour, minute, second matter; Before Firefox 49, timeRange(0, 23) will always evaluate to true. Now timeRange(23, 0) will only evaluate true if the current hour is 23:00 or midnight.

+
+ +

例子

+ +
timerange(12);                // returns true from noon to 1pm
+timerange(12, 13);            // returns true from noon to 1pm
+timerange(12, "GMT");         // returns true from noon to 1pm, in GMT timezone
+timerange(9, 17);             // returns true from 9am to 5pm
+timerange(8, 30, 17, 00);     // returns true from 8:30am to 5:00pm
+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";
+  }
+}
+ +
+

注意: 这是只有一个代理服务器情况下最简单高效的自动配置脚本。

+
+ +

例 2

+ +

和例 1 一样,但是对防火墙外的本地服务器使用代理

+ +

如果有主机(例如生产环境中的 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.orgmerchant.mozilla.org 也使用代理。

+ +
+

注意:以上例外的顺序影响效率:localHostOrDomainIs() 只在 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

+ +

基于网域(Subnet)的选择方案

+ +

在此示例中,所有同一子网内的主机均直接连接,其他主机则通过代理连接:

+ +
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 模式(pattern)的路由规划

+ +

This example is more sophisticated. There are four (4) proxy servers; one of them is a hot stand-by for all of the other ones, so if any of the remaining three goes down the fourth one will take over. Furthermore, the three remaining proxy servers share the load based on URL patterns, which makes their caching more effective (there is only one copy of any document on the three servers - as opposed to one copy on each of them). The load is distributed like this:

+ + + + + + + + + + + + + + + + + + + + + + + + +
代理用途
#1.com 域名
#2.edu 域名
#3所有其他域名
#4备用(原文:hot stand-by,活跃备用、热备用)
+ +

All local accesses are desired to be direct. All proxy servers run on the port 8080 (they don't need to, you can just change your port but remember to modify your configuations on both side). Note how strings can be concatenated with the + operator in 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() 中可用。作为例子,我们通过{{jsxref("String.prototype.startsWith()", "startsWith()")}} 为不同的协议设置不同的代理。

+ +
function FindProxyForURL(url, host) {
+
+  if (url.startsWith("http:"))
+    return "PROXY http-proxy.mydomain.com:8080";
+
+  else if (url.startsWith("ftp:"))
+    return "PROXY ftp-proxy.mydomain.com:8080";
+
+  else if (url.startsWith(“gopher:"))
+    return "PROXY gopher-proxy.mydomain.com:8080";
+
+  else if (url.startsWith("https:") || url.startsWith("snews:"))
+    return "PROXY security-proxy.mydomain.com:8080";
+
+  else
+    return "DIRECT";
+
+}
+ +
+

注意: shExpMatch() 也可以做到,例如:

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

自动配置脚本也可以在服务端动态生成。这在某些情况下比较有用,例如根据客户端地址指定不同的代理服务器。

+ +

isInNet()isResolvable()dnsResolve() 应该谨慎使用,这些函数会进行  DNS 查询。其他函数则大都是字符处理函数,不需要 DNS 。如果通过代理连接,代理本身也会进行一次 DNS 查询,这产生了额外的 DNS 请求。并且绝大多数情况下,不需要这些函数来实现特定的功能。

+
+ +

历史与实现

+ +

Proxy auto-config was introduced into Netscape Navigator 2.0 in the late 1990s, at the same time when JavaScript was introduced. Open-sourcing Netscape eventually lead to Firefox itself.

+ +

The most "original" implementation of PAC and its JavaScript libraries is, therefore, nsProxyAutoConfig.js found in early versions of Firefox. These utilities are found in many other open-source systems including Chromium. Firefox later integrated the file into ProxyAutoConfig.cpp as a string literal.

+ +

Microsoft in general made its own implementation. There used to be some problems with their libraries, but most are resolved by now. They have defined some new "Ex" suffixed functions around the address handling parts to support IPv6. The feature is supported by Chromium, but not yet by Firefox (bugzilla #558253).

diff --git a/files/zh-cn/web/http/server-side_access_control/index.html b/files/zh-cn/web/http/server-side_access_control/index.html deleted file mode 100644 index 50a52b3405..0000000000 --- a/files/zh-cn/web/http/server-side_access_control/index.html +++ /dev/null @@ -1,249 +0,0 @@ ---- -title: Server-Side Access Control -slug: Web/HTTP/Server-Side_Access_Control -tags: - - AJAX - - CORS - - HTTP - - PHP -translation_of: Web/HTTP/CORS -translation_of_original: Web/HTTP/Server-Side_Access_Control ---- -

{{HTTPSidebar}}

- -

浏览器会针对从 {{domxref("XMLHttpRequest")}} 或Fetch API中发起的跨网站请求发送特定的HTTP标头。它还希望看到使用跨站点响应发送回的特定HTTP标头。这些标头的概述,包括启动请求和处理来自服务器的响应的示例JavaScript代码, 以及每个头的讨论,可以在HTTP访问控制(CORS)文章中找到,应该作为本文的配套文章阅读。

- -

HTTP访问控制文章是很好的使用指南。本文介绍利用PHP处理访问控制请求和制定访问控制响应。本文的目标读者是服务器程序员或管理员。虽然在PHP代码示例所示,类似的概念适用于ASP.net,Perl、Python、Java等;一般来说,这些概念可以应用于任何服务器端编程环境处理HTTP请求和动态制定的HTTP响应。

- -

讨论HTTP标头

- -

了解HTTP 头部信息, 建议先阅读这篇文章 covering the HTTP headers used by both clients (such as Firefox 3.5 and beyond) and servers

- -
 
- -

工作代码示例

- -

随后的章节中PHP代码(和JavaScript调用服务器)可查看相关代码,这些代码在实现了XMLHttpRequest的浏览器上都可运行,像Firefox 3.5及以上。

- -
 
- -

简单的跨站请求

- -

简单的访问控制请求 在下列情况下会被发起:

- - - -

以下情况,请求会返回相关响应信息

- - - -

 简单的访问控制请求 介绍了在客户端和服务端进行信息交换的HEADER.  下面是一段用来处理简单请求的PHP代码。

- -
<?php
-
-// 我们将只授予 arunranga.com 域的访问权限,因为我们认为它通过 application/xml 方式来访问这些资源是安全的。
-
-if($_SERVER['HTTP_ORIGIN'] == "http://arunranga.com")
-{
-
-    header('Access-Control-Allow-Origin: http://arunranga.com');
-    header('Content-type: application/xml');
-    readfile('arunerDotNetResource.xml');
-}
-else
-{
-header('Content-Type: text/html');
-echo "<html>";
-echo "<head>";
-echo "   <title>Another Resource</title>";
-echo "</head>";
-echo "<body>",
-    "<p>This resource behaves two-fold:";
-echo "<ul>",
-        "<li>If accessed from <code>http://arunranga.com</code> it returns an XML document</li>";
-echo " <li>If accessed from any other origin including from simply typing in the URL into the browser's address bar,";
-echo "you get this HTML document</li>",
-    "</ul>",
-"</body>",
-"</html>";
-}
-?>
-
- -

上面的代码通过检查浏览器发送的 ORIGIN 头部信息(通过 $_SERVER['HTTP_ORIGIN'] ) 是否匹配 'http://arunranga.com' 得知,如果是,返回 Access-Control-Allow-Origin: http://arunranga.com 。如果你的浏览器支持访问控制,你可以访问 这里 .

- -

预请求

- -

预请求 发生在下列情况中:

- - - -

预请求访问控制 这篇文章介绍了在客户端和服务器间进行交换的头信息,响应preflight requests请求的服务器资源会有这些动作:

- - - -

下面是相关的PHP内容, preflighted request:

- -
<?php
-if($_SERVER['REQUEST_METHOD'] == "GET")
-{
-    header('Content-Type: text/plain');
-    echo "This HTTP resource is designed to handle POSTed XML input from arunranga.com and not be retrieved with GET";
-
-}
-elseif($_SERVER['REQUEST_METHOD'] == "OPTIONS")
-{
-    // 告诉客户端我们支持来自 arunranga.com 的请求并且预请求有效期将仅有20天
-    if($_SERVER['HTTP_ORIGIN'] == "http://arunranga.com")
-    {
-    header('Access-Control-Allow-Origin: http://arunranga.com');
-    header('Access-Control-Allow-Methods: POST, GET, OPTIONS');
-    header('Access-Control-Allow-Headers: X-PINGARUNER');
-    header('Access-Control-Max-Age: 1728000');
-    header("Content-Length: 0");
-    header("Content-Type: text/plain");
-    //exit(0);
-    }
-    else
-    {
-    header("HTTP/1.1 403 Access Forbidden");
-    header("Content-Type: text/plain");
-    echo "You cannot repeat this request";
-
-    }
-}
-elseif($_SERVER['REQUEST_METHOD'] == "POST")
-{
-    /* 通过首先获得XML传送过来的blob来处理POST请求,然后做一些处理, 最后将结果返回客户端
-    */
-    if($_SERVER['HTTP_ORIGIN'] == "http://arunranga.com")
-    {
-            $postData = file_get_contents('php://input');
-            $document = simplexml_load_string($postData);
-
-            // 对POST过来的数据进行一些处理
-
-            $ping = $_SERVER['HTTP_X_PINGARUNER'];
-
-
-            header('Access-Control-Allow-Origin: http://arunranga.com');
-            header('Content-Type: text/plain');
-            echo // 处理之后的一些响应
-    }
-    else
-        die("POSTing Only Allowed from arunranga.com");
-}
-else
-    die("No Other Methods Allowed");
-
-?>
-
- -

可以看到,就像POST一样,针对OPTIONS preflight请求,同样返回对应的头信息。这样 以来,处理preflight就像处理普通的request请求一样,在针对OPTIONS请求的响应信息中,服务器通过客户端,实际的请求可以用POST的形式发送,同时可附加X-PINGARUNERP这样的头信息。如果浏览器支持的话,可访问 这里

- -

凭证请求

- -

带凭据的请求,将Cookies和HTTP认证信息一起发送出去的跨域请求,根据请求方式,可以是 Simple 或 Preflighted,

- -

发送 简单请求 时, Firefox 3.5 (或以上)会发送带Cookies信息的请求,  (如果withCredentials 设以true). 如果服务器响应真的是可信任的, 客户端接受并进行输出。 在 预请求 中,服务器可以针对 OPTIONS 请求,返回 Access-Control-Allow-Credentials: true 信息

- -

下面是处理请求的PHP内容:

- -
<?php
-
-if($_SERVER['REQUEST_METHOD'] == "GET")
-{
-
-    // First See if There Is a Cookie
-    //$pageAccess = $_COOKIE['pageAccess'];
-    if (!isset($_COOKIE["pageAccess"])) {
-
-    setcookie("pageAccess", 1, time()+2592000);
-    header('Access-Control-Allow-Origin: http://arunranga.com');
-    header('Cache-Control: no-cache');
-    header('Pragma: no-cache');
-    header('Access-Control-Allow-Credentials: true');
-    header('Content-Type: text/plain');
-    echo 'I do not know you or anyone like you so I am going to mark you with a Cookie :-)';
-
-    }
-    else
-    {
-
-    $accesses = $_COOKIE['pageAccess'];
-    setcookie('pageAccess', ++$accesses, time()+2592000);
-    header('Access-Control-Allow-Origin: http://arunranga.com');
-    header('Access-Control-Allow-Credentials: true');
-    header('Cache-Control: no-cache');
-    header('Pragma: no-cache');
-    header('Content-Type: text/plain');
-    echo 'Hello -- I know you or something a lot like you!  You have been to ', $_SERVER['SERVER_NAME'], ' at least ', $accesses-1, ' time(s) before!';
-    }
-
-}
-elseif($_SERVER['REQUEST_METHOD'] == "OPTIONS")
-{
-    // Tell the Client this preflight holds good for only 20 days
-    if($_SERVER['HTTP_ORIGIN'] == "http://arunranga.com")
-    {
-    header('Access-Control-Allow-Origin: http://arunranga.com');
-    header('Access-Control-Allow-Methods: GET, OPTIONS');
-    header('Access-Control-Allow-Credentials: true');
-    header('Access-Control-Max-Age: 1728000');
-    header("Content-Length: 0");
-    header("Content-Type: text/plain");
-    //exit(0);
-    }
-    else
-    {
-    header("HTTP/1.1 403 Access Forbidden");
-    header("Content-Type: text/plain");
-    echo "You cannot repeat this request";
-
-    }
-}
-else
-    die("This HTTP Resource can ONLY be accessed with GET or OPTIONS");
-
-
-
-?>
-
- -

需要注意的是,在带凭据请求中, Access-Control-Allow-Origin: 头不能是通配符 "*",必须是一个有效的域名。  可参考这里 running here

- -

Apache示例

- -

限制对某些URI的访问

- -

最有效的方法之一,利用Apache rewrite, 环境变量,还有headers使Access-Control-Allow-* 对某些特定的URI生效,比如,以无认证信息形式利用GET跨域请求api(.*).json。

- -
RewriteRule ^/api(.*)\.json$ /api$1.json [CORS=True]
-Header set Access-Control-Allow-Origin "*" env=CORS
-Header set Access-Control-Allow-Methods "GET" env=CORS
-Header set Access-Control-Allow-Credentials "false" env=CORS
-
- -

参见

- - diff --git a/files/zh-cn/web/http/x-frame-options/index.html b/files/zh-cn/web/http/x-frame-options/index.html deleted file mode 100644 index 2b6cfcda76..0000000000 --- a/files/zh-cn/web/http/x-frame-options/index.html +++ /dev/null @@ -1,161 +0,0 @@ ---- -title: X-Frame-Options -slug: Web/HTTP/X-Frame-Options -tags: - - HTTP - - 响应头 - - 响应头部 - - 安全性 -translation_of: Web/HTTP/Headers/X-Frame-Options ---- -
{{HTTPSidebar}}
- -

The X-Frame-Options HTTP 响应头是用来给浏览器 指示允许一个页面 可否在 {{HTMLElement("frame")}}, {{HTMLElement("iframe")}}, {{HTMLElement("embed")}} 或者 {{HTMLElement("object")}} 中展现的标记。站点可以通过确保网站没有被嵌入到别人的站点里面,从而避免 {{interwiki("wikipedia", "clickjacking")}} 攻击。

- -

The added security is only provided if the user accessing the document is using a browser supporting X-Frame-Options. {{HTTPHeader("Content-Security-Policy")}} HTTP 头中的 frame-ancestors 指令会替代这个非标准的 header。CSP 的 frame-ancestors 会在 {{Gecko("4.0")}} 中支持,但是并不会被所有浏览器支持。然而 X-Frame-Options 是个已广泛支持的非官方标准,可以和 CSP 结合使用。

- - - - - - - - - - - - -
Header type{{Glossary("Response header")}}
{{Glossary("Forbidden header name")}}no
- -

语法

- -

X-Frame-Options 有三个可能的值:

- -
X-Frame-Options: deny
-X-Frame-Options: sameorigin
-X-Frame-Options: allow-from https://example.com/
-
- -

指南

- -

换一句话说,如果设置为 deny,不光在别人的网站 frame 嵌入时会无法加载,在同域名页面中同样会无法加载。另一方面,如果设置为sameorigin,那么页面就可以在同域名页面的 frame 中嵌套。

- -
-
deny
-
表示该页面不允许在 frame 中展示,即便是在相同域名的页面中嵌套也不允许。
-
sameorigin
-
表示该页面可以在相同域名页面的 frame 中展示。
-
allow-from uri
-
表示该页面可以在指定来源的 frame 中展示。
-
- -

例子

- -
-

Note: 设置 meta 标签是无效的!例如 <meta http-equiv="X-Frame-Options" content="deny"> 没有任何效果。不要这样用!只有当像下面示例那样设置 HTTP 头 X-Frame-Options 才会生效。

-
- -

配置 Apache

- -

配置 Apache 在所有页面上发送 X-Frame-Options 响应头,需要把下面这行添加到 'site' 的配置中:

- -
Header always set X-Frame-Options "sameorigin"
-
- -

要将 Apache 的配置 X-Frame-Options 设置成 deny , 按如下配置去设置你的站点:

- -
Header set X-Frame-Options "deny"
-
- -

要将 Apache 的配置 X-Frame-Options 设置成 allow-from,在配置里添加:

- -
Header set X-Frame-Options "allow-from https://example.com/"
-
- -

配置 nginx

- -

配置 nginx 发送 X-Frame-Options 响应头,把下面这行添加到 'http', 'server' 或者 'location' 的配置中:

- -
add_header X-Frame-Options sameorigin always;
-
- -

配置 IIS

- -

配置 IIS 发送 X-Frame-Options 响应头,添加下面的配置到 Web.config 文件中:

- -
<system.webServer>
-  ...
-
-  <httpProtocol>
-    <customHeaders>
-      <add name="X-Frame-Options" value="sameorigin" />
-    </customHeaders>
-  </httpProtocol>
-
-  ...
-</system.webServer>
-
- -

配置 HAProxy

- -

配置 HAProxy 发送 X-Frame-Options 头,添加这些到你的前端、监听 listen,或者后端的配置里面:

- -
rspadd X-Frame-Options:\ sameorigin
-
- -

或者,在更加新的版本中:

- -
http-response set-header X-Frame-Options sameorigin
-
- -

配置 Express

- -

要配置 Express 可以发送 X-Frame-Options header,你可以用借助了 frameguard 来设置头部的 helmet。在你的服务器配置里面添加:

- -
const helmet = require('helmet');
-const app = express();
-app.use(helmet.frameguard({ action: "sameorigin" }));
-
- -

或者,你也可以直接用 frameguard

- -
const frameguard = require('frameguard')
-app.use(frameguard({ action: 'sameorigin' }))
-
- -

结果

- -

在 Firefox 尝试加载 frame 的内容时,如果 X-Frame-Options 响应头设置为禁止访问了,那么 Firefox 会用 about:blank 展现到 frame 中。也许从某种方面来讲的话,展示为错误消息会更好一点。

- -

规范

- - - - - - - - - - - - - - -
规范标题
{{RFC("7034")}}HTTP Header Field X-Frame-Options
- -

浏览器兼容性

- - - -

{{Compat("http.headers.X-Frame-Options")}}

- -

参见

- - diff --git "a/files/zh-cn/web/http/\347\255\226\347\225\245\347\211\271\345\276\201/index.html" "b/files/zh-cn/web/http/\347\255\226\347\225\245\347\211\271\345\276\201/index.html" deleted file mode 100644 index 90e83fb04a..0000000000 --- "a/files/zh-cn/web/http/\347\255\226\347\225\245\347\211\271\345\276\201/index.html" +++ /dev/null @@ -1,153 +0,0 @@ ---- -title: Feature Policy -slug: Web/HTTP/策略特征 -translation_of: Web/HTTP/Feature_Policy ---- -
{{SeeCompatTable}}{{HTTPSidebar}}
- -

特征策略允许web开发者在浏览器中选择启用、禁用和修改确切特征和 API 的行为.比如{{Glossary("CSP","内容安全策略")}},但是它控制的是浏览器的特征非安全行为.

- -

概述

- -

特征策略提供了一种机制去声明哪些功能通过你的网络,是可以被用的(或者不被使用的)。这就允许你通过功能可用性来很好的锁定功能,即使代码很老,或者包含第三方的内容。

- -

有了功能策略,你可以选择一组“策略”,让浏览器强制执行整个网站使用的特定功能。这些策略限制了站点可以访问哪些api,或者修改浏览器对某些特性的默认行为

- -

使用特性策略可以做什么的示例?:

- - - -

概念和用法

- -

特性策略允许您在顶级页面和嵌入式框架中控制哪些源可以使用哪些特性。实际上,您编写了一个策略,它是每个特性允许的起源列表。对于由特性策略控制的每个特性,只有当它的起源与允许的起源列表匹配时,该特性才会在当前文档或框架中启用.

- -

对于每个策略控制的功能,浏览器都会维护启用该功能的来源列表,称为允许列表。如果您未为功能指定策略,则将使用默认的允许列表。默认的许可列表特定于每个功能.

- -

编写策略

- -

使用一组单独的策略指令来描述策略。策略指令是已定义功能名称和可以使用该功能的来源的允许列表的组合.

- -

指定策略

- -

功能策略提供了两种方法来指定用于控制功能的策略:

- - - -

HTTP标头和allow属性之间的主要区别在于allow属性仅控制iframe中的功能。标头控制响应中的功能以及页面内的任何嵌入式内容.

- -

点此链接查看更多详细信息 Using Feature Policy.

- -

策略控制功能的类型

- -

尽管功能策略使用一致的语法提供了对多个功能的控制,但是策略控制功能的行为却有所不同,并取决于多个因素.

- -

一般原则是,Web开发人员应该有一种直观或不间断的方式来检测或处理禁用该功能的情况。新引入的功能可能具有显示状态的显式API。稍后与功能策略集成的现有功能通常将使用现有机制。一些方法包括:

- - - -

当前的一组策略控制功能可分为两大类:

- - - -

良好用户体验的最佳实践

- -

有几种策略控制的功能可帮助实施最佳实践,以提供良好的性能和用户体验.

- -

在大多数情况下,策略控制的功能代表的功能在使用时会对用户体验产生负面影响。为避免破坏现有的Web内容,此类策略控制功能的默认设置是允许所有来源使用该功能。然后,通过使用禁用策略控制功能的策略来实施最佳实践。有关更多详细信息,请参见“实施最佳实践以提供良好的用户体验”.

- -

功能包括:

- - - -

精细控制某些功能

- -

Web提供的功能和API如果被滥用,可能会带来隐私或安全风险。在某些情况下,您可能希望严格限制在网站上使用此类功能的方式。有策略控制的功能,允许针对网站中的特定来源或框架启用/禁用功能。该功能在可用时与Permissions API或特定于功能的机制集成在一起,以检查该功能是否可用.

- -

功能包括:

- - - -

更多示例

- - - -

规范

- - - - - - - - - - - - - - -
说明书状态描述
{{SpecName('Feature Policy','#feature-policy-http-header-field','Feature-Policy')}}{{Spec2('Feature Policy')}}初始化前定义 {{httpheader('Feature-Policy')}} 头. 规范中定义了指令所控制的特性. 有关详细信息,请参阅个别指令页面.
- -

浏览器兼容性

- - - -

{{Compat("http.headers.Feature-Policy")}}

- -

参见

- - diff --git "a/files/zh-cn/web/http/\347\255\226\347\225\245\347\211\271\345\276\201/using_feature_policy/index.html" "b/files/zh-cn/web/http/\347\255\226\347\225\245\347\211\271\345\276\201/using_feature_policy/index.html" deleted file mode 100644 index 9a37fa46f3..0000000000 --- "a/files/zh-cn/web/http/\347\255\226\347\225\245\347\211\271\345\276\201/using_feature_policy/index.html" +++ /dev/null @@ -1,140 +0,0 @@ ---- -title: Using Feature Policy -slug: Web/HTTP/策略特征/Using_Feature_Policy -translation_of: Web/HTTP/Feature_Policy/Using_Feature_Policy ---- -
{{HTTPSidebar}} {{SeeCompatTable}}
- -

Feature Policy allows you to control which origins can use which features, both in the top-level page and in embedded frames. Essentially, you write a policy, which is an allowed list of origins for each feature. For every feature controlled by Feature Policy, the feature is only enabled in the current document or frame if its origin matches the allowed list of origins.

- -

For each policy-controlled feature, the browser maintains a list of origins for which the feature is enabled, known as an allowlist. If you do not specify a policy for a feature, then a default allowlist will be used. The default allowlist is specific to each feature.

- -

Writing a policy

- -

A policy is described using a set of individual policy directives. A policy directive is a combination of a defined feature name, and an allowlist of origins that can use the feature.

- -

allowlist

- -

allowlist可以使用以下一个或多个值。

- - - -

*(在所有源地址启用)'none'(在所有源地址禁用)只允许单独使用,而'self''src'可以与多个源地址一起使用。

- -

所有的特性都有一个如下的默认的allowlist

- - - -

Specifying your policy

- -

Feature Policy provides two ways to specify policies to control features:

- - - -

The primary difference between the HTTP header and the allow attribute is that the allow attribute only controls features within an iframe. The header controls features in the response and any embedded content within the page.

- -

The Feature-Policy HTTP header

- -

You can send the Feature-Policy HTTP header with the response of a page. The value of this header is a policy to be enforced by the browser for the given page. It has the following structure.

- -
Feature-Policy: <feature name> <allowlist of origin(s)>
- -

For example, to block all content from using the Geolocation API across your site:

- -
Feature-Policy: geolocation 'none'
- -

Several features can be controlled at the same time by sending the HTTP header with a semicolon-separated list of policy directives, or by sending a separate header for each policy.

- -

For example, the following are equivalent:

- -
Feature-Policy: unsized-media 'none'; geolocation 'self' https://example.com; camera *;
-
-Feature-Policy: unsized-media 'none'
-Feature-Policy: geolocation 'self' https://example.com
-Feature-Policy: camera *;
-
- -

The iframe allow attribute

- -

The second way to use Feature Policy is for controlling content within an iframe. Use the allow attribute to specify a policy list for embedded content.

- -

For example, allow all browsing contexts within this iframe to use fullscreen:

- -
<iframe src="https://example.com..." allow="fullscreen"></iframe>
- -

This is equivalent to:

- -
<iframe src="https://example.com..." allow="fullscreen 'src'"></iframe>
- -

This example allows <iframe> content on a particular origin to access the user's location:

- -
<iframe src="https://google-developers.appspot.com/demos/..."
-        allow="geolocation https://google-developers.appspot.com"></iframe>
-
- -

Similar to the HTTP header, several features can be controlled at the same time by specifying a semicolon-separated list of policy directives.

- -

For example, this blocks the <iframe> from using the camera and microphone:

- -
<iframe allow="camera 'none'; microphone 'none'">
-
- -

Inheritance of policy for embedded content

- -

Scripts inherit the policy of their browsing context, regardless of their origin. That means that top-level scripts inherit the policy from the main document.

- -

All iframes inherit the policy of their parent page. If the iframe has an allow attribute, the policies of the parent page and the allow attribute are combined, using the most restrictive subset. For an iframe to have a feature enabled, the origin must be in the allowlist for both the parent page and the allow attribute.

- -

Disabling a feature in a policy is a one-way toggle. If a feature has been disabled for a child frame by its parent frame, the child cannot re-enable it, and neither can any of the child's descendants.

- -

Enforcing best practices for good user experiences

- -

It's difficult to build a website that uses all the latest best practices and provides great performance and user experiences. As the website evolves, it can become even harder to maintain the user experience over time. You can use feature policies to specify the desired best practices, and rely on the browser to enforce the policies to prevent regressions.

- -

There are several policy-controlled features designed to represent functionality that can negatively impact the user experience. These features include:

- - - -

To avoid breaking existing web content, the default for such policy-controlled features is to allow the functionality to be used by all origins. That is, the default allowlist is '*' for each feature. Preventing the use of the sub-optimal functionality requires explicitly specifying a policy that disables the features.

- -

For new content, you can start developing with a policy that disables all the features. This approach ensures that none of the functionality is introduced. When applying a policy to existing content, testing is likely required to verify it continues to work as expected. This is especially important for embedded or third-party content that you do not control.

- -

To turn on the enforcement of all the best practices, specify the policy as below.

- -

Send the following the HTTP header:

- -
Feature-Policy: layout-animations 'none'; unoptimized-images 'none'; oversized-images 'none'; sync-script 'none'; sync-xhr 'none'; unsized-media 'none';
- -

Using the <iframe> allow attribute:

- -
<iframe src="https://example.com..." allow="layout-animations 'none'; unoptimized-images 'none'; oversized-images 'none'; sync-script 'none'; sync-xhr 'none'; unsized-media 'none';"></iframe>
- -

See also

- - diff --git "a/files/zh-cn/web/http/\350\267\250\345\237\237\350\265\204\346\272\220\345\205\261\344\272\253(cors)_/index.html" "b/files/zh-cn/web/http/\350\267\250\345\237\237\350\265\204\346\272\220\345\205\261\344\272\253(cors)_/index.html" deleted file mode 100644 index 5d4f591eb7..0000000000 --- "a/files/zh-cn/web/http/\350\267\250\345\237\237\350\265\204\346\272\220\345\205\261\344\272\253(cors)_/index.html" +++ /dev/null @@ -1,544 +0,0 @@ ---- -title: 跨域资源共享(CORS) -slug: Web/HTTP/跨域资源共享(CORS)_ ---- -
{{ HTTPSidebar }}
- -
- -
跨域资源共享({{Glossary("CORS")}}) 是一种机制,它使用额外的 {{Glossary("HTTP")}} 头来告诉浏览器  让运行在一个 origin (domain) 上的Web应用被准许访问来自不同源服务器上的指定的资源。当一个资源从与该资源本身所在的服务器不同的域、协议或端口请求一个资源时,资源会发起一个跨域 HTTP 请求
- -
- -
如,站点 http://domain-a.com 的某 HTML 页面通过 <img> 的 src 请求 http://domain-b.com/image.jpg。网络上的许多页面都会加载来自不同域的CSS样式表,图像和脚本等资源。
- -
- -

出于安全原因,浏览器限制从脚本内发起的跨源HTTP请求。 例如,XMLHttpRequest和Fetch API遵循同源策略。 这意味着使用这些API的Web应用程序只能从加载应用程序的同一个域请求HTTP资源,除非响应报文包含了正确CORS响应头。

- -

  (译者注:这段描述不准确,并不一定是浏览器限制了发起跨站请求,也可能是跨站请求可以正常发起,但是返回结果被浏览器拦截了。)

- -

- -

跨域资源共享( {{Glossary("CORS")}} )机制允许 Web 应用服务器进行跨域访问控制,从而使跨域数据传输得以安全进行。现代浏览器支持在 API 容器中(例如 {{domxref("XMLHttpRequest")}} 或 Fetch )使用 CORS,以降低跨域 HTTP 请求所带来的风险。

- -

谁应该读这篇文章?

- -

说实话,每个人。

- -

更具体地来讲,这篇文章适用于网站管理员、后端和前端开发者。现代浏览器处理跨域资源共享的客户端部分,包括HTTP头和相关策略的执行。但是这一新标准意味着服务器需要处理新的请求头和响应头。对于服务端的支持,开发者可以阅读补充材料 cross-origin sharing from a server perspective (with PHP code snippets)

- -

什么情况下需要 CORS ?

- -

跨域资源共享标准( cross-origin sharing standard )允许在下列场景中使用跨域 HTTP 请求:

- - - -

本文概述了跨域资源共享机制及其所涉及的 HTTP 头。

- -

功能概述

- -

跨域资源共享标准新增了一组 HTTP 首部字段,允许服务器声明哪些源站通过浏览器有权限访问哪些资源。另外,规范要求,对那些可能对服务器数据产生副作用的 HTTP 请求方法(特别是 {{HTTPMethod("GET")}} 以外的 HTTP 请求,或者搭配某些 MIME 类型的 {{HTTPMethod("POST")}} 请求),浏览器必须首先使用 {{HTTPMethod("OPTIONS")}} 方法发起一个预检请求(preflight request),从而获知服务端是否允许该跨域请求。服务器确认允许之后,才发起实际的 HTTP 请求。在预检请求的返回中,服务器端也可以通知客户端,是否需要携带身份凭证(包括 Cookies 和 HTTP 认证相关数据)。

- -

CORS请求失败会产生错误,但是为了安全,在JavaScript代码层面是无法获知到底具体是哪里出了问题。你只能查看浏览器的控制台以得知具体是哪里出现了错误。

- -

接下来的内容将讨论相关场景,并剖析该机制所涉及的 HTTP 首部字段。

- -

若干访问控制场景

- -

这里,我们使用三个场景来解释跨域资源共享机制的工作原理。这些例子都使用 {{domxref("XMLHttpRequest")}} 对象。

- -

本文中的 JavaScript 代码片段都可以从 http://arunranga.com/examples/access-control/ 获得。另外,使用支持跨域  {{domxref("XMLHttpRequest")}} 的浏览器访问该地址,可以看到代码的实际运行结果。

- -

关于服务端对跨域资源共享的支持的讨论,请参见这篇文章: Server-Side_Access_Control (CORS)

- -

简单请求

- -

某些请求不会触发 CORS 预检请求。本文称这样的请求为“简单请求”,请注意,该术语并不属于 {{SpecName('Fetch')}} (其中定义了 CORS)规范。若请求满足所有下述条件,则该请求可视为“简单请求”:

- - - -
注意: 这些跨域请求与浏览器发出的其他跨域请求并无二致。如果服务器未返回正确的响应首部,则请求方不会收到任何数据。因此,那些不允许跨域请求的网站无需为这一新的 HTTP 访问控制特性担心。
- -
注意: WebKit Nightly 和 Safari Technology Preview 为{{HTTPHeader("Accept")}}, {{HTTPHeader("Accept-Language")}}, 和 {{HTTPHeader("Content-Language")}} 首部字段的值添加了额外的限制。如果这些首部字段的值是“非标准”的,WebKit/Safari 就不会将这些请求视为“简单请求”。WebKit/Safari 并没有在文档中列出哪些值是“非标准”的,不过我们可以在这里找到相关讨论:Require preflight for non-standard CORS-safelisted request headers Accept, Accept-Language, and Content-Language, Allow commas in Accept, Accept-Language, and Content-Language request headers for simple CORS, and Switch to a blacklist model for restricted Accept headers in simple CORS requests。其它浏览器并不支持这些额外的限制,因为它们不属于规范的一部分。
- -

比如说,假如站点 http://foo.example 的网页应用想要访问 http://bar.other 的资源。http://foo.example 的网页中可能包含类似于下面的 JavaScript 代码:

- -
var invocation = new XMLHttpRequest();
-var url = 'http://bar.other/resources/public-data/';
-
-function callOtherDomain() {
-  if(invocation) {
-    invocation.open('GET', url, true);
-    invocation.onreadystatechange = handler;
-    invocation.send();
-  }
-}
-
- -

客户端和服务器之间使用 CORS 首部字段来处理跨域权限:

- -

- -

分别检视请求报文和响应报文:

- -
GET /resources/public-data/ HTTP/1.1
-Host: bar.other
-User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre
-Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
-Accept-Language: en-us,en;q=0.5
-Accept-Encoding: gzip,deflate
-Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
-Connection: keep-alive
-Referer: http://foo.example/examples/access-control/simpleXSInvocation.html
-Origin: http://foo.example
-
-
-HTTP/1.1 200 OK
-Date: Mon, 01 Dec 2008 00:23:53 GMT
-Server: Apache/2.0.61
-Access-Control-Allow-Origin: *
-Keep-Alive: timeout=2, max=100
-Connection: Keep-Alive
-Transfer-Encoding: chunked
-Content-Type: application/xml
-
-[XML Data]
-
- -

第 1~10 行是请求首部。第10行 的请求首部字段 {{HTTPHeader("Origin")}} 表明该请求来源于 http://foo.example

- -

第 13~22 行是来自于 http://bar.other 的服务端响应。响应中携带了响应首部字段 {{HTTPHeader("Access-Control-Allow-Origin")}}(第 16 行)。使用 {{HTTPHeader("Origin")}} 和 {{HTTPHeader("Access-Control-Allow-Origin")}} 就能完成最简单的访问控制。本例中,服务端返回的 Access-Control-Allow-Origin: * 表明,该资源可以被任意外域访问。如果服务端仅允许来自 http://foo.example 的访问,该首部字段的内容如下:

- -

Access-Control-Allow-Origin: http://foo.example

- -

现在,除了 http://foo.example,其它外域均不能访问该资源(该策略由请求首部中的 ORIGIN 字段定义,见第10行)。Access-Control-Allow-Origin 应当为 * 或者包含由 Origin 首部字段所指明的域名。

- -

预检请求

- -

与前述简单请求不同,“需预检的请求”要求必须首先使用 {{HTTPMethod("OPTIONS")}}   方法发起一个预检请求到服务器,以获知服务器是否允许该实际请求。"预检请求“的使用,可以避免跨域请求对服务器的用户数据产生未预期的影响。

- -

当请求满足下述任一条件时,即应首先发送预检请求:

- - - -
-

注意: WebKit Nightly 和 Safari Technology Preview 为{{HTTPHeader("Accept")}}, {{HTTPHeader("Accept-Language")}}, 和 {{HTTPHeader("Content-Language")}} 首部字段的值添加了额外的限制。如果这些首部字段的值是“非标准”的,WebKit/Safari 就不会将这些请求视为“简单请求”。WebKit/Safari 并没有在文档中列出哪些值是“非标准”的,不过我们可以在这里找到相关讨论:Require preflight for non-standard CORS-safelisted request headers Accept, Accept-Language, and Content-Language, Allow commas in Accept, Accept-Language, and Content-Language request headers for simple CORS, and Switch to a blacklist model for restricted Accept headers in simple CORS requests。其它浏览器并不支持这些额外的限制,因为它们不属于规范的一部分。

-
- -

如下是一个需要执行预检请求的 HTTP 请求:

- -
var invocation = new XMLHttpRequest();
-var url = 'http://bar.other/resources/post-here/';
-var body = '<?xml version="1.0"?><person><name>Arun</name></person>';
-
-function callOtherDomain(){
-  if(invocation)
-    {
-      invocation.open('POST', url, true);
-      invocation.setRequestHeader('X-PINGOTHER', 'pingpong');
-      invocation.setRequestHeader('Content-Type', 'application/xml');
-      invocation.onreadystatechange = handler;
-      invocation.send(body);
-    }
-}
-
-......
-
- -

上面的代码使用 POST 请求发送一个 XML 文档,该请求包含了一个自定义的请求首部字段(X-PINGOTHER: pingpong)。另外,该请求的 Content-Type 为 application/xml。因此,该请求需要首先发起“预检请求”。

- -

- -
OPTIONS /resources/post-here/ HTTP/1.1
-Host: bar.other
-User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre
-Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
-Accept-Language: en-us,en;q=0.5
-Accept-Encoding: gzip,deflate
-Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
-Connection: keep-alive
-Origin: http://foo.example
-Access-Control-Request-Method: POST
-Access-Control-Request-Headers: X-PINGOTHER, Content-Type
-
-
-HTTP/1.1 200 OK
-Date: Mon, 01 Dec 2008 01:15:39 GMT
-Server: Apache/2.0.61 (Unix)
-Access-Control-Allow-Origin: http://foo.example
-Access-Control-Allow-Methods: POST, GET, OPTIONS
-Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
-Access-Control-Max-Age: 86400
-Vary: Accept-Encoding, Origin
-Content-Encoding: gzip
-Content-Length: 0
-Keep-Alive: timeout=2, max=100
-Connection: Keep-Alive
-Content-Type: text/plain
- -

预检请求完成之后,发送实际请求:

- -
POST /resources/post-here/ HTTP/1.1
-Host: bar.other
-User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre
-Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
-Accept-Language: en-us,en;q=0.5
-Accept-Encoding: gzip,deflate
-Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
-Connection: keep-alive
-X-PINGOTHER: pingpong
-Content-Type: text/xml; charset=UTF-8
-Referer: http://foo.example/examples/preflightInvocation.html
-Content-Length: 55
-Origin: http://foo.example
-Pragma: no-cache
-Cache-Control: no-cache
-
-<?xml version="1.0"?><person><name>Arun</name></person>
-
-
-HTTP/1.1 200 OK
-Date: Mon, 01 Dec 2008 01:15:40 GMT
-Server: Apache/2.0.61 (Unix)
-Access-Control-Allow-Origin: http://foo.example
-Vary: Accept-Encoding, Origin
-Content-Encoding: gzip
-Content-Length: 235
-Keep-Alive: timeout=2, max=99
-Connection: Keep-Alive
-Content-Type: text/plain
-
-[Some GZIP'd payload]
- -

浏览器检测到,从 JavaScript 中发起的请求需要被预检。从上面的报文中,我们看到,第 1~12 行发送了一个使用 OPTIONS 方法的“预检请求”。 OPTIONS 是 HTTP/1.1 协议中定义的方法,用以从服务器获取更多信息。该方法不会对服务器资源产生影响。 预检请求中同时携带了下面两个首部字段:

- -
Access-Control-Request-Method: POST
-Access-Control-Request-Headers: X-PINGOTHER, Content-Type
- -

首部字段 Access-Control-Request-Method 告知服务器,实际请求将使用 POST 方法。首部字段 Access-Control-Request-Headers 告知服务器,实际请求将携带两个自定义请求首部字段:X-PINGOTHER 与 Content-Type。服务器据此决定,该实际请求是否被允许。

- -

第14~26 行为预检请求的响应,表明服务器将接受后续的实际请求。重点看第 17~20 行:

- -
Access-Control-Allow-Origin: http://foo.example
-Access-Control-Allow-Methods: POST, GET, OPTIONS
-Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
-Access-Control-Max-Age: 86400
- -

首部字段 Access-Control-Allow-Methods 表明服务器允许客户端使用 POST, GET OPTIONS 方法发起请求。该字段与 HTTP/1.1 Allow: response header 类似,但仅限于在需要访问控制的场景中使用。

- -

首部字段 Access-Control-Allow-Headers 表明服务器允许请求中携带字段 X-PINGOTHER Content-Type Access-Control-Allow-Methods 一样,Access-Control-Allow-Headers 的值为逗号分割的列表。

- -

最后,首部字段 Access-Control-Max-Age 表明该响应的有效时间为 86400 秒,也就是 24 小时。在有效时间内,浏览器无须为同一请求再次发起预检请求。请注意,浏览器自身维护了一个最大有效时间,如果该首部字段的值超过了最大有效时间,将不会生效。

- -

预检请求与重定向

- -

大多数浏览器不支持针对于预检请求的重定向。如果一个预检请求发生了重定向,浏览器将报告错误:

- -
-

The request was redirected to 'https://example.com/foo', which is disallowed for cross-origin requests that require preflight

-
- -
-

Request requires preflight, which is disallowed to follow cross-origin redirect

-
- -

CORS 最初要求该行为,不过在后续的修订中废弃了这一要求

- -

在浏览器的实现跟上规范之前,有两种方式规避上述报错行为:

- - - -

如果上面两种方式难以做到,我们仍有其他办法:

- - - -

不过,如果请求是由于存在 Authorization 字段而引发了预检请求,则这一方法将无法使用。这种情况只能由服务端进行更改。

- -

附带身份凭证的请求

- -

Fetch 与 CORS 的一个有趣的特性是,可以基于  HTTP cookies 和 HTTP 认证信息发送身份凭证。一般而言,对于跨域 {{domxref("XMLHttpRequest")}} 或 Fetch 请求,浏览器不会发送身份凭证信息。如果要发送凭证信息,需要设置 XMLHttpRequest 的某个特殊标志位。

- -

本例中,http://foo.example 的某脚本向 http://bar.other 发起一个GET 请求,并设置 Cookies:

- -
var invocation = new XMLHttpRequest();
-var url = 'http://bar.other/resources/credentialed-content/';
-
-function callOtherDomain(){
-  if(invocation) {
-    invocation.open('GET', url, true);
-    invocation.withCredentials = true;
-    invocation.onreadystatechange = handler;
-    invocation.send();
-  }
-}
- -

第 7 行将 XMLHttpRequest 的 withCredentials 标志设置为 true,从而向服务器发送 Cookies。因为这是一个简单 GET 请求,所以浏览器不会对其发起“预检请求”。但是,如果服务器端的响应中未携带 Access-Control-Allow-Credentials: true ,浏览器将不会把响应内容返回给请求的发送者。

- -

- -

客户端与服务器端交互示例如下:

- -
GET /resources/access-control-with-credentials/ HTTP/1.1
-Host: bar.other
-User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre
-Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
-Accept-Language: en-us,en;q=0.5
-Accept-Encoding: gzip,deflate
-Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
-Connection: keep-alive
-Referer: http://foo.example/examples/credential.html
-Origin: http://foo.example
-Cookie: pageAccess=2
-
-
-HTTP/1.1 200 OK
-Date: Mon, 01 Dec 2008 01:34:52 GMT
-Server: Apache/2.0.61 (Unix) PHP/4.4.7 mod_ssl/2.0.61 OpenSSL/0.9.7e mod_fastcgi/2.4.2 DAV/2 SVN/1.4.2
-X-Powered-By: PHP/5.2.6
-Access-Control-Allow-Origin: http://foo.example
-Access-Control-Allow-Credentials: true
-Cache-Control: no-cache
-Pragma: no-cache
-Set-Cookie: pageAccess=3; expires=Wed, 31-Dec-2008 01:34:53 GMT
-Vary: Accept-Encoding, Origin
-Content-Encoding: gzip
-Content-Length: 106
-Keep-Alive: timeout=2, max=100
-Connection: Keep-Alive
-Content-Type: text/plain
-
-
-[text/plain payload]
- -

即使第 11 行指定了 Cookie 的相关信息,但是,如果 bar.other 的响应中缺失 {{HTTPHeader("Access-Control-Allow-Credentials")}}: true(第 19 行),则响应内容不会返回给请求的发起者。

- -

附带身份凭证的请求与通配符

- -

对于附带身份凭证的请求,服务器不得设置 Access-Control-Allow-Origin 的值为“*”。

- -

这是因为请求的首部中携带了 Cookie 信息,如果 Access-Control-Allow-Origin 的值为“*”,请求将会失败。而将 Access-Control-Allow-Origin 的值设置为 http://foo.example,则请求将成功执行。

- -

另外,响应首部中也携带了 Set-Cookie 字段,尝试对 Cookie 进行修改。如果操作失败,将会抛出异常。

- -

HTTP 响应首部字段

- -

本节列出了规范所定义的响应首部字段。上一小节中,我们已经看到了这些首部字段在实际场景中是如何工作的。

- -

Access-Control-Allow-Origin

- -

响应首部中可以携带一个 {{HTTPHeader("Access-Control-Allow-Origin")}} 字段,其语法如下:

- -
Access-Control-Allow-Origin: <origin> | *
-
- -

其中,origin 参数的值指定了允许访问该资源的外域 URI。对于不需要携带身份凭证的请求,服务器可以指定该字段的值为通配符,表示允许来自所有域的请求。

- -

例如,下面的字段值将允许来自 http://mozilla.com 的请求:

- -
Access-Control-Allow-Origin: http://mozilla.com
- -

如果服务端指定了具体的域名而非“*”,那么响应首部中的 Vary 字段的值必须包含 Origin。这将告诉客户端:服务器对不同的源站返回不同的内容。

- -

Access-Control-Expose-Headers

- -

译者注:在跨域访问时,XMLHttpRequest对象的getResponseHeader()方法只能拿到一些最基本的响应头,Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma,如果要访问其他头,则需要服务器设置本响应头。

- -

{{HTTPHeader("Access-Control-Expose-Headers")}} 头让服务器把允许浏览器访问的头放入白名单,例如:

- -
Access-Control-Expose-Headers: X-My-Custom-Header, X-Another-Custom-Header
-
- -

这样浏览器就能够通过getResponseHeader访问X-My-Custom-Header和 X-Another-Custom-Header 响应头了。

- -

Access-Control-Max-Age

- -

{{HTTPHeader("Access-Control-Max-Age")}} 头指定了preflight请求的结果能够被缓存多久,请参考本文在前面提到的preflight例子。

- -
Access-Control-Max-Age: <delta-seconds>
-
- -

delta-seconds 参数表示preflight请求的结果在多少秒内有效。

- -

Access-Control-Allow-Credentials

- -

{{HTTPHeader("Access-Control-Allow-Credentials")}} 头指定了当浏览器的credentials设置为true时是否允许浏览器读取response的内容。当用在对preflight预检测请求的响应中时,它指定了实际的请求是否可以使用credentials。请注意:简单 GET 请求不会被预检;如果对此类请求的响应中不包含该字段,这个响应将被忽略掉,并且浏览器也不会将相应内容返回给网页。

- -
Access-Control-Allow-Credentials: true
-
- -

上文已经讨论了附带身份凭证的请求

- -

Access-Control-Allow-Methods

- -

{{HTTPHeader("Access-Control-Allow-Methods")}} 首部字段用于预检请求的响应。其指明了实际请求所允许使用的 HTTP 方法。

- -
Access-Control-Allow-Methods: <method>[, <method>]*
-
- -

相关示例见这里

- -

Access-Control-Allow-Headers

- -

{{HTTPHeader("Access-Control-Allow-Headers")}} 首部字段用于预检请求的响应。其指明了实际请求中允许携带的首部字段。

- -
Access-Control-Allow-Headers: <field-name>[, <field-name>]*
-
- -

HTTP 请求首部字段

- -

本节列出了可用于发起跨域请求的首部字段。请注意,这些首部字段无须手动设置。 当开发者使用 XMLHttpRequest 对象发起跨域请求时,它们已经被设置就绪。

- -

Origin

- -

{{HTTPHeader("Origin")}} 首部字段表明预检请求或实际请求的源站。

- -
Origin: <origin>
-
- -

origin 参数的值为源站 URI。它不包含任何路径信息,只是服务器名称。

- -
Note: 有时候将该字段的值设置为空字符串是有用的,例如,当源站是一个 data URL 时。
- -

注意,不管是否为跨域请求,ORIGIN 字段总是被发送。

- -

Access-Control-Request-Method

- -

{{HTTPHeader("Access-Control-Request-Method")}} 首部字段用于预检请求。其作用是,将实际请求所使用的 HTTP 方法告诉服务器。

- -
Access-Control-Request-Method: <method>
-
- -

相关示例见这里

- -

Access-Control-Request-Headers

- -

{{HTTPHeader("Access-Control-Request-Headers")}} 首部字段用于预检请求。其作用是,将实际请求所携带的首部字段告诉服务器。

- -
Access-Control-Request-Headers: <field-name>[, <field-name>]*
-
- -

相关示例见这里

- -

规范

- - - - - - - - - - - - - - - - - - - -
SpecificationStatusComment
{{SpecName('Fetch', '#cors-protocol', 'CORS')}}{{Spec2('Fetch')}}New definition; supplants CORS specification.
{{SpecName('CORS')}}{{Spec2('CORS')}}Initial definition.
- -

浏览器兼容性

- - - -

{{Compat("http.headers.Access-Control-Allow-Origin")}}

- -

- - - -

参见

- - - -

{{ languages( { "ja": "ja/HTTP_access_control" } ) }}

-- cgit v1.2.3-54-g00ecf