默认状况下,为预防某些而已行为,浏览器的XHR对象只能访问来源于同一个域中的资源。可是咱们在平常实际开发中,经常会遇到跨域请求的需求,所以就出现了一种跨域请求的方案:CORS(Cross-Origin Resource Sharing)跨域资源共享。
CORS背后的原理是:使用自定的HTTP头部与服务器进行沟通,从而由服务器决定响应是否成功。api
使用CORS须要客户端和服务端二者配合。跨域
目前在大多数浏览器下(CORS在各浏览器下支持状况),都原生支持CORS,代码编写时和同域的请求差很少,只须要在xhr.open()的时候传入绝对URL便可。例如:浏览器
var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function () { if(xhr.readyState == 4){ if(xhr.status >= 200 && xhr.status < 300 || xhr.status == 304){ console.log(xhr.responseText) }else { console.log('err' + xhr.status); } } }; xhr.open('get','http://www.xxx.com/api/something/',true); xhr.send(null);
这样就能够发送一个跨域请求了,可是若是只是如上面示例代码同样发送的话会报错,由于服务器并未设置容许咱们这个请求,所以CORS还须要服务端来配合。缓存
服务器只须要在响应头部中设置Access-Control-Allow-Origin便可让客户端访问。安全
假设客户端的域名是http://www.xxx.com,那么服务端只要在Access-Control-Allow-Origin的设置中含有http://www.xxx.com,那么这个CORS请求便可成功。若是Access-Control-Allow-Origin设置为*,那么任意域名均可以访问这个服务端,可是为了安全起见,通常并不建议这样作。服务器
如下截图是一个CORS请求后服务端正常返回的示例:并发
CORS还有一种叫作Preflighted Request(预飞请求)的透明服务器验证机制完成请求过程,若是你在请求的时候使用了表1中的选项来发送请求(使用setRequestheaders设定自定义头部),那么就会触发Preflighted Request,它的请求过程以下:cors
1.XHR对象send发出请求url
2.浏览器先向服务端发出一个OPTIONS方法的请求,并发送下列头部:code
请求头部信息 | 含义 |
---|---|
Origin | 来源域名,与简单的请求相同。 |
Access-Control-Request-Method | 请求自身使用的方法。 |
Access-Control-Request-Headers (可选) | 自定义的头部信息,多个头部以逗号分隔。 |
OPTIONS请求示例:
客户端请求的代码(比上面多加了个header):
var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function () { if(xhr.readyState == 4){ if(xhr.status >= 200 && xhr.status < 300 || xhr.status == 304){ console.log(xhr.responseText) }else { console.log('err' + xhr.status); } } }; xhr.open('get','http://www.xxx.com/api/poisearch/',true); xhr.setRequestHeader('haha',1); xhr.send(null);
请求结果(这里OPTIONS请求触发了,但没有找到这个url):
3.服务器接收到这个请求后,根据上面的头部信息判断是否予以接收。并在响应中发送以下头部与浏览器进行沟通:
响应头部信息 | 含义 |
---|---|
Access-Control-Allow-Origin | 来源域名,与简单的请求相同。 |
Access-Control-Allow-Methods | 容许的方法,多个方法以逗号分隔。 |
Access-Control-Allow-Headers(可选) | 容许的头部,多个头部以逗号分隔。 |
Access-Control-Max-Age | 应该将这个Preflight请求缓存多长时间(以秒表示) |
4.Preflighted Request结束后,结果将按照指定的时间缓存起来。
5.若是服务端判断上面设置的额外信息能够容许请求,那么就会再请求一次正常的请求了。