XHR 是受同源策略的限制,
跨源资源共享(CORS,Cross-Origin Resource Sharing)定义了浏览器与服务器如何实现跨源通信

CORS 基本思路

使用自定义的 HTTP 头部允许浏览器和服务器相互了解,以确实请求或响应应该成功还是失败。
对于简单请求,没有自定义头部,请求体为 text/plain 类型,发送请求时会有一个额外 Origin 头部。


Origin 头部包括包含发送请求的页面的源 (协议、域名和端口)

服务器会进行 决定可以跨域加发送 Access-Control-Allow-Origin 的头部,包含相同的源或者是“*”公开资源

如果没有这个头部或者不配匹,表明不会响应浏览器请求

XHR 使用 CORS 访问

现代浏览器通过 XMLHttpRequest 对象原生支持 CORS。在尝试访问不同源的资源时,这个行为 会被自动触发。要向不同域的源发送请求,可以使用标准 XHR 对象并给 open()方法传入一个绝对 URL

  1. let xhr = new XMLHttpRequest();
  2. xhr.onreadystatechange = function() {
  3. if (xhr.readyState == 4) {
  4. if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
  5. alert(xhr.responseText);
  6. } else {
  7. alert("Request was unsuccessful: " + xhr.status);
  8. }
  9. }
  10. };
  11. xhr.open("get", "http://www.somewhere-else.com/page/", true);
  12. xhr.send(null);

跨源 XHR

对象些额外限制

  • 不能使用 setRequestHeader() 设置自定义头部
  • 不能发送和接收 cookie
  • getAllResponseHeaders() 方法始终返回空字符串

    预检请求 preflighted request

    CORS 通过预检请求通过 OPTIONS 方法对服务器验证

  • 允许使用自定义头部

  • 支持除 GET 和 POST 之外的方法,
  • 不两只请求体内容

浏览器 OPTIONS 方法的头部

  • Origin 与简单请求相同
  • Access-Control-Request-Method 请求希望使用的方法
  • Access-Control-Request-Headers (可选)要使用逗号分隔的自定义头部列表

服务器响应发送头部

  • Access-Control-Allow-Origin 与简单请求相同
  • Access-Control-Allow-Method 允许的方法(逗号分隔的列表)
  • Access-Control-Allow-Headers 服务器允许的头部(逗号分隔的列表)
  • Access-Control-Max-Age 缓存预请求的,即第一次发送这种的请求时隔多久才会再发送一次额外的 HTTP 请求

    凭据请求

    默认跨源不提供凭据(cookie、HTTP 认证和客户端 SSL 证书),可通过 withCredentials 为 true 来表明请求会发送凭据。
    服务器允许,响应 HTTP 头部

  • Access-Control-Allow-Credentials: true

如果发送了凭据请求而服务器返回的响应中没有这个头部,则浏览器不会把响应交给 JavaScript (responseText 空字符串,status 是 0,onerror()被调用)。
注意,服务器也可以在预检请求的 响应中发送这个 HTTP 头部,以表明这个源允许发送凭据请求。

替代性跨源技术

CORS 出现之前,实现跨源 Ajax 通信是有点麻烦的。开发者需要依赖能够执行跨源请求的 DOM 特 性,在不使用 XHR 对象情况下发送某种类型的请求。虽然 CORS 目前已经得到广泛支持,但这些技术 仍然没有过时,因为它们不需要修改服务器。