预备知识:
- 只有浏览器才会有跨域请求限制,也就是如果是服务器之间直接发起http请求不会存在该限制。
- CORS是在不满足同源策略的情况下,才有可能引起跨域请求限制。
- 同源策略校验包括protocol + host/domain + port(80/443会省略),只有三者完全相同是,才满足同源策略。
- <script><img><iframe><link><video><audio>带有src属性,浏览器允许跨域请求
- 表单提交、重定向允许跨域写操作(此时可能引起CSRF,可以通过埋token的方式避免)
- 浏览器不支持跨站点访问Cookie、LocalStorage、IndexDB
- 浏览器不支持跨站点访问DOM
- 浏览器不支持跨站点的AJAX请求,在不进行跨域请求配置的情况下。
跨域请求的解决方案:
-
简单请求
- 请求method只能是GET/POST/HEAD
- 仅能使用CORS安全的Header: Accept、Accept-Language、Content-Language、Content-Type
- Content-Tytpe只能是如下的一种:text/plain、multipart/form-data、applicaton/x-www-form-urlencoded
- 请求中必须携带Origin头部,服务端通过响应Access-Control-Allow-Origin头部来只是浏览器该如何处理该请求(如果Access-Control-Allow-Origin为Origin的值或者为*时,浏览器才允许渲染请求结果)
复杂请求
请求示例:
- 创建html文件,内部含有Ajax请求(http://127.0.0.1:8081和http://127.0.0.1:8082不满足同源策略)
<html>
<body>
<p>跨域请求测试</p>
<p id="resp"></p>
<script>
var invocation = new XMLHttpRequest();
var url = "http://127.0.0.1:8082";
function handler() {
if (invocation.readyState == 4) {
if (invocation.status==200) {
console.log(invocation.responseText);
document.getElementById('resp').innerHTML=invocation.responseText;
}
}
}
function callOtherDomain() {
if (invocation) {
invocation.open('GET', url, true);
invocation.onreadystatechange = handler;
invocation.send();
}
}
callOtherDomain();
</script>
</body>
</html>%
```html
2. 配置nginx server
server {
listen 8081;
server_name localhost;
charset utf-8;
location / {
# 这个地方需要修改成你上面保存的cors.html的目录
root /path-to-directory;
index cors.html cors.htm;
}
}
server {
listen 8082;
server_name localhost;
charset utf-8;
location / {
return 200 'hello world';
}
}
保存,执行nginx -s reload
-
打开浏览器,访问http://127.0.0.1:8081。你将会发现http://127.0.0.1:8082的Ajax请求失败了,浏览器提示CORS error(MissingAllowOriginHeader) 。
但是通过抓包可以看到,nginx其实将相应('hello world')返回给浏览器了,但是由于不满足CORS policy,相应被浏览器隐藏了。抓包截图:
3.1 修改8082站点的配置,以允许来自8081的跨站请求
server {
listen 8082;
server_name localhost;
charset utf-8;
location / {
add_header Access-Control-Allow-Origin 'http://127.0.0.1:8081';
return 200 'hello world';
}
}
再次刷新浏览器,可以发现请求正常返回了
因为Response header中返回了Access-Control-Allow-Origin: http://127.0.0.1:8081
4. 更多的跨域请求响应Header
5. 常见错误
5.1 MultipleAllowOriginValues
Access to XMLHttpRequest at 'http://127.0.0.1:8082/' from origin 'http://127.0.0.1:8081' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header contains multiple values 'http://127.0.0.1:8081, http://127.0.0.1:8083', but only one is allowed.
原因:response header中返回了多个AccessControlAllowOrigin值(可以是相同的,也可以是不同的)。例如如下的服务端返回:
server {
listen 8082;
server_name localhost;
charset utf-8;
location / {
add_header Access-Control-Allow-Origin 'http://127.0.0.1:8081';
add_header Access-Control-Allow-Origin 'http://127.0.0.1:8081';
return 200 'hello world';
}
}
Access-Control-Allow-Origin只能返回一个源
add_header Access-Control-Allow-Origin 'http://127.0.0.1:8081';
add_header Access-Control-Allow-Origin 'http://127.0.0.1:8083';
这种不同的源也是不行的,即使相同的源也是不行的。
add_header Access-Control-Allow-Origin 'http://127.0.0.1:8081,http://127.0.0.1:8083';
这种也是不行的