CORS是一个W3C标准,全称是“跨域资源共享”,它允许浏览器向跨源服务器,发出XHR请求,克服了AJAX的同源限制。
实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。
浏览器将CORS请求分成两类:简单请求和非简单请求。浏览器对这两种请求的处理是不一样
简单请求:
对于简单请求,浏览器直接发出CORS请求,就是在头信息之中,增加一个Origin
字段。
Origin字段用来说明,本次请求来自哪个源,服务器根据这个值,决定是否同意这次请求。如果Origin指定的源,不再许可范围内,服务器会返回一个正常的HTTP回应,但是这个回应的头信息没有包含Access-Control-Allow-Origin
字段,浏览器就知道出错了,从而抛出一个错误,被XHR
的onerror
回调函数捕获。并且,这种错误无法通过状态码识别,因为HTTP回应的状态码有可能是200。
如果Origin
指定的域名在许可范围内,服务器返回的响应,会多出几个头信息字段:
上面头信息中,有三个与CORS请求相关的字段,都以Access-Control-
开头:
1.Access-Control-Allow-Origin:该字段是必须的,它的值要么是请求时Origin字段的值,要么是一个*,表示接受任意域名的请求。
2.Access-Control-Allow-Credentials:该字段可选,它是一个布尔值,表示是否允许发送Cookie。这个值也只能设为true,如果服务器不要浏览器发送Cookie,删除该字段即可。
3.Access-Control-Expose-Headers:该字段可选,用于指定getResponseHeader方法可以返回的字段值。
withCredentials 属性:
CORS请求默认不发送Cookie和HTTP认证信息。如果要把Cookie发到服务器,一方面要服务器同意,指定Access-Control-Allow-Credentials
字段,另一方面,开发者必须在AJAX请求中打开withCredentials
属性。需要注意的是,如果要发送Cookie,Access-Control-Allow-Origin
就不能设为星号,必须指定明确的、与请求网页一致的域名
非简单请求:
预检请求:
非简单请求是那种对服务器有特殊要求的请求,比如请求方法是PUT
或DELETE
,或者Content-Type
字段的类型是application/json。
浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP动词和头信息字段。只有得到肯定答复,浏览器才会发出正式的XMLHttpRequest
请求,否则就报错。
浏览器的正常请求和回应:
一旦服务器通过了"预检"请求,以后每次浏览器正常的CORS请求,就都跟简单请求一样,会有一个Origin
头信息字段。服务器的回应,也都会有一个Access-Control-Allow-Origin
头信息字段。
总结:
在之前的demo项目中,我也有遇到过跨域的问题,我是不论收到什么请求,都给响应头加上了Access-Control-Allow-Origin:“ * ”,来解决这跨域的问题,现在看来这种方式还是太粗暴了。这种方式的原理在于,跨域只存在于浏览器上,服务器端是不存在跨域问题的,所以当浏览器端发出跨域请求时,我们可以利用CORS的规则,人为的改变响应头