跨域是是因为浏览器的同源策略限制,是浏览器的一种安全机制,服务端之间是不存在跨域的。
所谓同源指的是两个页面具有相同的协议、主机和端口,三者有任一不相同即会产生跨域。
在了解cors解决跨域之前,我们先来了解一下什么是简单请求和非简单请求。
工作中比较常见的简单请求:
、
multipart/form-data、
text/plain中的一种。满足以上条件的即为简单请求,否则即为非简单请求。
工作中常见的非简单请求:
对于简单请求:
浏览器发现是跨域请求,就会自动在请求头中加上Origin字段,代表请求来自哪个域(协议+主机名+端口号)。服务器在收到请求后,根据请求头中Origin字段值来判断是否允许跨域请求通过。具体实现方法是:在响应头Access-Control-Allow-Origin字段中设置指定的域名,表示允许这些域名的跨域请求。如果请求头中Origin字段的域名包含在这些域名中,则可以实现跨域请求(当然有时候还需要结合其他字段来判断),否则不通过。例如:
请求头信息:
GET /cors HTTP/1.1
Origin: http://localhost:8080/
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...
Origin字段说明本次请求来自:http://localhost:8080/。
响应头信息:
Access-Control-Allow-Origin: http://localhost:8080/
Access-Control-Allow-Credentials: true
Content-Type: text/html; charset=utf-8
说明 http://localhost:8080/在服务器允许的范围内。
Access-Control-Allow-Credentials字段代表服务器允许cookie可以包含在请求中,一起发送给服务器,值为布尔类型。如果要把cookie一起发送到服务器,还需要在请求中打开withCredentials
属性。
var xhr = new XMLHttpRequest();
xhr.withCredentials = true;
注意:如果要发送cookie,Access-Control-Allow-Origin的值不能为“*”,只能是具体的域名。
非简单请求:
非简单请求在发送http请求时,会预先发送一次“预检”(OPTIONS)请求。预检请求会事先询问服务器,当前域名是否在服务器允许的范围内,以及可以使用哪些HTTP动词和头信息字段。只有得到肯定答复后,浏览器才会真正发出http请求,否则就会报错。例如:
var url = 'http://localhost:8080/';
var xhr = new XMLHttpRequest();
xhr.open('PUT', url, true);
xhr.setRequestHeader('Header-1', 'value');
xhr.send();
上述代码中,http发送了一条PUT请求,并且自定义请求头信息Header-1.
Access-Control-Allow-Origin: http://localhost:8080/
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: Header-1
Content-Type: text/html; charset=utf-8
Access-Control-Max-Age: 3600
上述http响应中,说明服务器允许http://localhost:8080/请求数据,
Access-Control-Max-Age表示本次预检请求的有限期,单位为秒,在此期间内,不用发出另一条预检请求。
一旦服务器通过了“预检”请求,以后每次浏览器正常请求CORS请求,就跟简单请求一样。会有Origin字段,响应头里也会有对应的Access-Control-Allow-Origin字段。
经过网关的在网关统一处理,没经过网关的在nginx做处理
http://www.ruanyifeng.com/blog/2016/04/cors.html