一文带你了解 HTTP 黑科技( 九 )


const invocation = new XMLHttpRequest();const 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 上的标志 , 必须设置该标志才能使用 Cookie 进行调用 。默认情况下 , 调用是不在使用 Cookie 的情况下进行的 。由于这是一个简单的 GET 请求 , 因此不会进行预检 , 但是浏览器将拒绝任何没有 Access-Control-Allow-Credentials 的响应:标头为true , 指的是响应不会返回 web 页面的内容 。
上面的请求用下图可以表示

一文带你了解 HTTP 黑科技

文章插图
 
这是客户端和服务器之间的示例交换:
GET /resources/access-control-with-credentials/ HTTP/1.1Host: bar.otherUser-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:71.0) Gecko/20100101 Firefox/71.0Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8Accept-Language: en-us,en;q=0.5Accept-Encoding: gzip,deflateConnection: keep-aliveReferer: http://foo.example/examples/credential.htmlOrigin: http://foo.exampleCookie: pageAccess=2HTTP/1.1 200 OKDate: Mon, 01 Dec 2008 01:34:52 GMTServer: Apache/2Access-Control-Allow-Origin: https://foo.exampleAccess-Control-Allow-Credentials: trueCache-Control: no-cachePragma: no-cacheSet-Cookie: pageAccess=3; expires=Wed, 31-Dec-2008 01:34:53 GMTVary: Accept-Encoding, OriginContent-Encoding: gzipContent-Length: 106Keep-Alive: timeout=2, max=100Connection: Keep-AliveContent-Type: text/plain[text/plain payload]上面第10行包含指向http://bar.other 上的内容 Cookie , 但是如果 bar.other 没有以 Access-Control-Allow-Credentials:true 响应(下面第五行) , 响应将被忽略 , 并且不能使用网站返回的内容 。
请求凭证和通配符
当回应凭证请求时 , 服务器必须在 Access-Control-Allow-Credentials 中指定一个来源 , 而不能直接写* 通配符
因为上面示例代码中的请求标头包含 Cookie 标头 , 如果 Access-Control-Allow-Credentials 中是指定的通配符 * 的话 , 请求会失败 。
注意上面示例中的 Set-Cookie 响应标头还设置了另外一个值 , 如果发生故障 , 将引发异常(取决于所使用的API) 。
HTTP 响应标头下面会列出一些服务器跨域共享规范定义的 HTTP 标头 , 上面简单概述了一下 , 现在一起来认识一下 , 主要会介绍下面这些
  • Access-Control-Allow-Origin
  • Access-Control-Allow-Credentials
  • Access-Control-Allow-Headers
  • Access-Control-Allow-Methods
  • Access-Control-Expose-Headers
  • Access-Control-Max-Age
  • Access-Control-Request-Headers
  • Access-Control-Request-Method
  • Origin
Access-Control-Allow-OriginAccess-Control-Allow-Origin 是 HTTP 响应标头 , 指示响应是否能够和给定的源共享资源 。Access-Control-Allow-Origin 指定单个资源会告诉浏览器允许指定来源访问资源 。对于没有凭据的请求 *通配符 , 告诉浏览器允许任何源访问资源 。
例如 , 如果要允许源 https://mozilla.org 的代码访问资源 , 可以使用如下的指定方式
Access-Control-Allow-Origin: https://mozilla.orgVary: Origin如果服务器指定单个来源而不是*通配符 , 则服务器还应在 Vary 响应标头中包含该来源 。
Access-Control-Allow-CredentialsAccess-Control-Allow-Credentials 是 HTTP 的响应标头 , 这个标头告诉浏览器 , 当包含凭证请求(Request.credentials)时是否将响应公开给前端 JavaScript 代码 。
这时候你会问到 Request.credentials 是什么玩意?不要着急 , 来给你看一下 , 首先来看 Request 是什么玩意 , 
实际上 , Request 是 Fetch API 的一类接口代表着资源请求 。一般创建 Request 对象有两种方式
  • 使用 Request() 构造函数创建一个 Request 对象
  • 还可以通过 FetchEvent.request api 操作来创建
再来说下 Request.credentials 是什么意思 , Request 接口的凭据只读属性指示在跨域请求的情况下 , 用户代理是否应从其他域发送 cookie 。(其他 Request 对象的方法详见 https://developer.mozilla.org/en-US/docs/Web/API/Request)
当发送的是凭证模式的请求包含 (Request.credentials)时 , 如果 Access-Control-Allow-Credentials 值为 true , 浏览器将仅向前端 JavaScript 代码公开响应 。


推荐阅读