通过XHR 进行Ajax 通信的一个主要限制是跨源安全策略。默认情况下,XHR 只能访问与发起请
求的页面在同一个域内的资源。这个安全限制可以防止某些恶意行为。不过,浏览器也需要支持合法跨
源访问的能力。
跨源资源共享(CORS,Cross-Origin Resource Sharing)定义了浏览器与服务器如何实现跨源通信。
CORS 背后的基本思路就是使用自定义的HTTP 头部允许浏览器和服务器相互了解,以确实请求或响应
应该成功还是失败。
对于简单的请求,比如GET 或POST 请求,没有自定义头部,而且请求体是text/plain 类型,
这样的请求在发送时会有一个额外的头部叫Origin。Origin 头部包含发送请求的页面的源(协议、
域名和端口),以便服务器确定是否为其提供响应。下面是Origin 头部的一个示例:
Origin: http://www.nczonline.net
如果服务器决定响应请求,那么应该发送Access-Control-Allow-Origin 头部,包含相同的源;
或者如果资源是公开的,那么就包含"*"。比如:
Access-Control-Allow-Origin: http://www.nczonline.net
如果没有这个头部,或者有但源不匹配,则表明不会响应浏览器请求。否则,服务器就会处理这个
请求。注意,无论请求还是响应都不会包含cookie 信息。
现代浏览器通过XMLHttpRequest 对象原生支持CORS。在尝试访问不同源的资源时,这个行为
会被自动触发。要向不同域的源发送请求,可以使用标准XHR对象并给open()方法传入一个绝对URL,
比如:
let xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
alert(xhr.responseText);
} else {
alert("Request was unsuccessful: " + xhr.status);
}
}
};
xhr.open(“get”, “http://www.somewhere-else.com/page/”, true);
xhr.send(null);
跨域XHR 对象允许访问status 和statusText 属性,也允许同步请求。出于安全考虑,跨域XHR
对象也施加了一些额外限制。
不能使用setRequestHeader()设置自定义头部。
不能发送和接收cookie。
getAllResponseHeaders()方法始终返回空字符串。
因为无论同域还是跨域请求都使用同一个接口,所以最好在访问本地资源时使用相对URL,在访问
远程资源时使用绝对URL。这样可以更明确地区分使用场景,同时避免出现访问本地资源时出现头部或
cookie 信息访问受限的问题。
预检请求
CORS 通过一种叫预检请求(preflighted request)的服务器验证机制,允许使用自定义头部、除GET
和POST 之外的方法,以及不同请求体内容类型。在要发送涉及上述某种高级选项的请求时,会先向服
务器发送一个“预检”请求。这个请求使用OPTIONS 方法发送并包含以下头部。
Origin:与简单请求相同。
Access-Control-Request-Method:请求希望使用的方法。
Access-Control-Request-Headers:(可选)要使用的逗号分隔的自定义头部列表。
下面是一个假设的POST 请求,包含自定义的NCZ 头部:
Origin: http://www.nczonline.net
Access-Control-Request-Method: POST
Access-Control-Request-Headers: NCZ
在这个请求发送后,服务器可以确定是否允许这种类型的请求。服务器会通过在响应中发送如下头部与浏览器沟通这些信息。
Access-Control-Allow-Origin:与简单请求相同。
Access-Control-Allow-Methods:允许的方法(逗号分隔的列表)。
Access-Control-Allow-Headers:服务器允许的头部(逗号分隔的列表)。
Access-Control-Max-Age:缓存预检请求的秒数。
例如:
Access-Control-Allow-Origin: http://www.nczonline.net
Access-Control-Allow-Methods: POST, GET
Access-Control-Allow-Headers: NCZ
Access-Control-Max-Age: 1728000
预检请求返回后,结果会按响应指定的时间缓存一段时间。换句话说,只有第一次发送这种类型的
请求时才会多发送一次额外的HTTP 请求。
凭据请求
默认情况下,跨源请求不提供凭据(cookie、HTTP 认证和客户端SSL 证书)。可以通过将
withCredentials 属性设置为true 来表明请求会发送凭据。如果服务器允许带凭据的请求,那么可
以在响应中包含如下HTTP 头部:
Access-Control-Allow-Credentials: true
如果发送了凭据请求而服务器返回的响应中没有这个头部,则浏览器不会把响应交给JavaScript
(responseText 是空字符串,status 是0,onerror()被调用)。注意,服务器也可以在预检请求的
响应中发送这个HTTP 头部,以表明这个源允许发送凭据请求。
07-21
03-08
8万+
![](https://csdnimg.cn/release/blogv2/dist/pc/img/readCountWhite.png)
06-01