CORS ———— 跨域解决方案之二 - Go语言中文社区

CORS ———— 跨域解决方案之二


其他跨域方案请看:

1、JSONP跨域方案

 

以下介绍CORS跨域解决方案

一、什么是CORS?

CORS (Corss-Orign Resource Sharing) 是W3C工作草案,是一份浏览器技术的规范。定义了跨域资源访问时,浏览器和服务器之间如何通信,使用自定义的http头部允许浏览器和服务器相互了解对方,从而决定请求或响应成功与否。CORS在现代浏览器都支持,使用和普通的ajax没有任何区别,关键是只要服务器实现CORS接口。

 

二、如何使用

现代浏览器都支持CORS,所以前端不需要做任何改变,即使普通的ajax,只需要服务器实现CORS接口;http如何请求服务器,我们不会有如何感觉。

 

三、服务端处理流程

 

HTTP请求

1、查看http头部是否有Origin,没有直接结束,有到第2步。

2、查看Origin是否有效,无效则返回403,有效则第3步。

3、查看method是否有效,无效则返回403,是有效则第4步。

4、查看是否是OPTION请求,不是则简单请求处理,是则预检处理。

 

简单请求处理:

返回Allow-Origin, Allow-Credentials等,并返回正常内容

 

预检处理:

返回Allow-Origin, Allow-Credentials等,内容为空,只有当浏览器下一次发出实际http请求才返回内容

 

四、客户端处理机制

浏览器将CORS请求分成两类:简单请求和预检请求(非简单请求),不需要做其他设置

划分的依据为:

(1) 简单请求(需要同时满足下面两个条件)

         请求方法是:HEAD ,GET,POST 三者之一

         HTTP头信息不超过以下字段:Accept,Accept-Language,Content-Language,Last-Event-ID,Content-Type(只限于三个值application/x-www-form-urlencodedmultipart/form-datatext/plain)

 

        简单请求时,浏览器会直接发起一个跨域请求,并在请求头中携带上Origin,用来说明本次请求来自哪个源。服务器端接受到请求后,根据头信息来判断是否允许跨域,返回一个正常的HTTP响应(如果允许,则响应头携带Access-Control-Allow-Origin等字段,并返回正常内容)。浏览器根据返回的响应头是否携带Access-Control-Allow-Origin等字段判断请求是否请求成功,没有则抛出异常。注意:请求是否成功不能通过状态码来确定,因为有可能也是200,但是请求拒绝了。

    

       异常:

       正确:

(2) 非简单请求

只要不能同时满足简单请求中任意一个条件的就是非简单请求,如果预检成功,浏览器实际一共会发送两次请求。

分别:

option请求

预检成功则发送正常的post请求

 

五、服务器端配置

服务器端可以在多个地方设置,比如ngnix、oss、cdn、web服务器等

主要涉及到的是:

Name Required Comments
Access-Control-Allow-Origin 必填 允许请求的域,比如:http://www.baidu.com或者所有都允许*
Access-Control-Allow-Methods 必填 允许请求的方法,比如:get、post、put、delete,多个用逗号分割,或者允许所有*
Access-Control-Allow-Headers 可选 预检请求后,告知发送请求需要有的头部
Access-Control-Expose-Headers 可选

CORS请求时,xmlhttprequest默认只能拿到6个基本字段:Cache-Control、

Content-Language、Content-Type、Expires、Last-Modified、Pragma。如果想拿

到其他字段,就必须在Access-Control-Expose-Headers里面指定。

Access-Control-Max-Age 可选 本次预检的有效期,单位:秒;在有效期内不需要发出另一条预检
Access-Control-Allow-Credentials 可选

表示是否允许发送cookie,默认false;比如put或delete,浊者content-type为

application/json等的有特殊要求,需要设置为true

 

1、web服务器

可以通过添加过滤器,或拦截器等处理

<filter>
	<display-name>CORSFilter</display-name>
	<filter-name>CORSFilter</filter-name>
	<filter-class>com.learn.mybatis.controller.filter.CORSFilter</filter-class>
</filter>
<filter-mapping>
	<filter-name>CORSFilter</filter-name>
	<url-pattern>/home</url-pattern>
</filter-mapping>
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    HttpServletResponse response2 = (HttpServletResponse) response;
    response2.setHeader("Access-Control-Allow-Origin", "*");
    response2.setHeader("Access-Control-Allow-Methods", "GET,POST,PUT,DELETE");
    response2.setHeader("Access-Control-Allow-Headers", "Content-Type,Authorization");
    response2.setHeader("Access-Control-Max-Age", "10");
	    
	chain.doFilter(request, response2);
}

 

2、ngnix

来源:https://michielkalkman.com/snippets/nginx-cors-open-configuration/

location / {
  if ($request_method = 'OPTIONS') {
    add_header 'Access-Control-Allow-Origin' '*';
    #
    # Om nom nom cookies
    #
    add_header 'Access-Control-Allow-Credentials' 'true';
    add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
    #
    # Custom headers and headers various browsers **should** be OK with but aren't
    #
    add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
    #
    # Tell client that this pre-flight info is valid for 20 days
    #
    add_header 'Access-Control-Max-Age' 1728000;
    add_header 'Content-Type' 'text/plain charset=UTF-8';
    add_header 'Content-Length' 0;
    return 204;
  }
  if ($request_method = 'POST') {
    add_header 'Access-Control-Allow-Origin' '*';
    add_header 'Access-Control-Allow-Credentials' 'true';
    add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
    add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
  }
  if ($request_method = 'GET') {
    add_header 'Access-Control-Allow-Origin' '*';
    add_header 'Access-Control-Allow-Credentials' 'true';
    add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
    add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
  }
}

 

3、oss

比如阿里云中,

  1. 进入OSS管理控制台界面。
  2. 在左侧存储空间列表中,单击目标存储空间名称,打开该存储空间概览页面。
  3. 单击基础设置页签,找到跨域设置区域,然后单击设置。

 

4、cdn

 

 

六、带认证的请求

CORS默认情况下是不需要提供cookie,http认证,ssl等的,如果需要携带认证,则需要设置

xmlhttprequest.withCredentials = true;

服务器端需要设置:

Access-Control-Allow-Credentials为true。

不然会报错:

当服务器设置带认证,则Access-Control-Allow-Origin不能设置为*,必须为一个具体的域名。

不然也会报错:

设置正确后,将携带上cookie:

 

七、错误处理

因为CORS错误,浏览器有可能返回的也是200,所以通过状态码无法判定是否出错。

可以使用onerror监听错误,使用onload检测成功

xhr.onerror = function(){
    conlose.log("cors error");
}

 

八、弊端、缺陷

1、只要服务器Access-Control-Allow-Origin不要设置成*,同时做好认证,在安全性上是比较可靠的,但是在低版本浏览器上并不支持,只能使用jsonp。

2、这点比较重要,CORS的两种请求方式:简单请求和非简单请求;即第一种是先发起请求,然后拦截返回数据;第二种是先请求验证进行拦截,再发起请求。

     所以对于简单请求来讲,即使返回数据被拦截,但是实际走过了后台的整个逻辑,即更新数据库的更新数据库等,但是到浏览器端却通过onerror报请求失败。

 

九、JSONP和CORS比较

Name Compare Usage
安全性

因为JSONP不是规范,所以存在很明显的安全漏洞,比如callback注入等。

但是安全没有绝对性,CORS也同样存在漏洞。CORS简单请求失败也会更新数据,这个漏洞在简单请求中存在。

 
兼容性 JSONP兼容型很强,CORS只支持现在浏览器,低版本ie等不支持 低版本使用JSONP,现在浏览器推荐CORS
请求方式 JSONP只能使用GET,CORS支持所有的http请求 有增删改查,推荐使用CORS
错误处理 JSONP错误处理不完善,CORS可以监听onerror,并通过浏览器控制台查看  
复杂度 JSONP发送一次get请求,CORS非简单请求会发送两次,第一次预检  

参考:

https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS

 

 

版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/nainaiqiuwencun/article/details/83003168
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
  • 发表于 2019-09-01 17:21:43
  • 阅读 ( 993 )
  • 分类:

0 条评论

请先 登录 后评论

官方社群

GO教程

推荐文章

猜你喜欢