跨域请求CORS

预备知识:

  1. 只有浏览器才会有跨域请求限制,也就是如果是服务器之间直接发起http请求不会存在该限制。
  2. CORS是在不满足同源策略的情况下,才有可能引起跨域请求限制。
  3. 同源策略校验包括protocol + host/domain + port(80/443会省略),只有三者完全相同是,才满足同源策略。
  4. <script><img><iframe><link><video><audio>带有src属性,浏览器允许跨域请求
  5. 表单提交、重定向允许跨域写操作(此时可能引起CSRF,可以通过埋token的方式避免)
  6. 浏览器不支持跨站点访问Cookie、LocalStorage、IndexDB
  7. 浏览器不支持跨站点访问DOM
  8. 浏览器不支持跨站点的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的值或者为*时,浏览器才允许渲染请求结果)
  • 复杂请求

请求示例:

  1. 创建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

  1. 打开浏览器,访问http://127.0.0.1:8081。你将会发现http://127.0.0.1:8082的Ajax请求失败了,浏览器提示CORS error(MissingAllowOriginHeader) 。
    但是通过抓包可以看到,nginx其实将相应('hello world')返回给浏览器了,但是由于不满足CORS policy,相应被浏览器隐藏了。抓包截图:


    image.png

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

image.png

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';
这种也是不行的

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容