預(yù)備知識(shí):
- 只有瀏覽器才會(huì)有跨域請(qǐng)求限制,也就是如果是服務(wù)器之間直接發(fā)起http請(qǐng)求不會(huì)存在該限制。
- CORS是在不滿足同源策略的情況下,才有可能引起跨域請(qǐng)求限制。
- 同源策略校驗(yàn)包括protocol + host/domain + port(80/443會(huì)省略),只有三者完全相同是,才滿足同源策略。
- <script><img><iframe><link><video><audio>帶有src屬性,瀏覽器允許跨域請(qǐng)求
- 表單提交、重定向允許跨域?qū)懖僮鳎ù藭r(shí)可能引起CSRF,可以通過(guò)埋token的方式避免)
- 瀏覽器不支持跨站點(diǎn)訪問(wèn)Cookie、LocalStorage、IndexDB
- 瀏覽器不支持跨站點(diǎn)訪問(wèn)DOM
- 瀏覽器不支持跨站點(diǎn)的AJAX請(qǐng)求,在不進(jìn)行跨域請(qǐng)求配置的情況下。
跨域請(qǐng)求的解決方案:
-
簡(jiǎn)單請(qǐng)求
- 請(qǐng)求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
- 請(qǐng)求中必須攜帶Origin頭部,服務(wù)端通過(guò)響應(yīng)Access-Control-Allow-Origin頭部來(lái)只是瀏覽器該如何處理該請(qǐng)求(如果Access-Control-Allow-Origin為Origin的值或者為*時(shí),瀏覽器才允許渲染請(qǐng)求結(jié)果)
復(fù)雜請(qǐng)求
請(qǐng)求示例:
- 創(chuàng)建html文件,內(nèi)部含有Ajax請(qǐng)求(http://127.0.0.1:8081和http://127.0.0.1:8082不滿足同源策略)
<html>
<body>
<p>跨域請(qǐng)求測(cè)試</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 / {
# 這個(gè)地方需要修改成你上面保存的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';
}
}
保存,執(zhí)行nginx -s reload
-
打開瀏覽器,訪問(wèn)http://127.0.0.1:8081。你將會(huì)發(fā)現(xiàn)http://127.0.0.1:8082的Ajax請(qǐng)求失敗了,瀏覽器提示CORS error(MissingAllowOriginHeader) 。
但是通過(guò)抓包可以看到,nginx其實(shí)將相應(yīng)('hello world')返回給瀏覽器了,但是由于不滿足CORS policy,相應(yīng)被瀏覽器隱藏了。抓包截圖:
image.png
3.1 修改8082站點(diǎn)的配置,以允許來(lái)自8081的跨站請(qǐng)求
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';
}
}
再次刷新瀏覽器,可以發(fā)現(xiàn)請(qǐng)求正常返回了
因?yàn)镽esponse header中返回了Access-Control-Allow-Origin: http://127.0.0.1:8081
4. 更多的跨域請(qǐng)求響應(yīng)Header

5. 常見錯(cuò)誤
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中返回了多個(gè)AccessControlAllowOrigin值(可以是相同的,也可以是不同的)。例如如下的服務(wù)端返回:
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只能返回一個(gè)源
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';
這種也是不行的
