详解 CORS跨域的几种不同实现方式

Posted zhaosq

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了详解 CORS跨域的几种不同实现方式相关的知识,希望对你有一定的参考价值。

CORS 定义

CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing),它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。提供了 Web 服务从不同域传来沙盒脚本的方法,以避开浏览器的同源策略,是 JSONP 模式的现代版。与 JSONP 不同,CORS 除了 GET 要求方法以外也支持其他的 HTTP 要求。用 CORS 可以让网页设计师用一般的 XMLHttpRequest,这种方式的错误处理比 JSONP 要来的好。另一方面,JSONP 可以在不支持 CORS 的老旧浏览器上运作。现代的浏览器都支持 CORS。

CORS是W3c工作草案,它定义了在跨域访问资源时浏览器和服务器之间如何通信。CORS背后的基本思想是使用自定义的HTTP头部允许浏览器和服务器相互了解对方,从而决定请求或响应成功与否。W3C CORS 工作草案
同源策略:是浏览器最核心也最基本的安全功能;同源指的是:同协议,同域名和同端口。精髓:认为自任何站点装载的信赖内容是不安全的。当被浏览器半信半疑的脚本运行在沙箱时,它们应该只被允许访问来自同一站点的资源,而不是那些来自其它站点可能怀有恶意的资源;参考:JavaScript 的同源策略
JSON & JSONP:JSON 是一种基于文本的数据交换方式,或者叫做数据描述格式。JSONP是资料格式JSON的一种“使用模式”,可以让网页从别的网域要资料,由于同源策略,一般来说位于server1.example.com的网页无法与不是 server1.example.com的服务器沟通,而html的script元素是一个例外。利用script元素的这个开放策略,网页可以得到从其他来源动态产生的JSON资料,而这种使用模式就是所谓的JSONP

CORS 对比 JSONP

都能解决 Ajax直接请求普通文件存在跨域无权限访问的问题

  1. JSONP只能实现GET请求,而CORS支持所有类型的HTTP请求
  2. 使用CORS,开发者可以使用普通的XMLHttpRequest发起请求和获得数据,比起JSONP有更好的错误处理
  3. JSONP主要被老的浏览器支持,它们往往不支持CORS,而绝大多数现代浏览器都已经支持了CORS

CORS,BROWSER支持情况

数据来源:caniuse.com

IE6,IE7,Opera min 不支持CORS。具体可参看数据来源中的 ‘show all‘

技术图片

主要用途

  • From a browser script perspective: By allowing cross-domain requests, which are subject to tighter controls on the types of data that is exchanged. Cookies, for instance, are blocked unless specifically requested by the XHR author and allowed by the cross-domain web service. This is done to mitigate the risk of data leaks.
  • From a web service perspective: By utilising the origin URL reported by the browser the target cross-domain web service can determine, based on its origin policy, whether to allow or deny the request.
  • 从浏览器脚本的角度来看:通过允许跨域请求,对交换的数据类型进行更严格的控制。例如,除非XHR作者特别要求并且跨域Web服务允许,否则将阻止cookie。这样做是为了降低数据泄漏的风险。
  • 从Web服务的角度来看:通过使用浏览器报告的源URL,目标跨域Web服务可以根据其源策略确定是否允许或拒绝请求。

Ajax请求跨域资源的异常

当出现如下异常时,那么就需要考虑跨域的问题了
例如 localhost:63343 通过Ajax请求http://192.168.10.61:8080服务器资源时就会出现如下异常:

技术图片

CORS 实现思路

CORS背后的基本思想是使用自定义的HTTP头部允许浏览器和服务器相互了解对方,从而决定请求或响应成功与否

安全说明

CORS is not about providing server-side security. The Origin request header is produced by the browser and the server has no direct means to verify it.

CORS 并不是为了解决服务端安全问题,而是为了解决如何跨域调用资源。至于如何设计出 安全的开放API,却是另一个问题了,这里提下一些思路:

  1. 请求时间有效性(验证timestamp与服务接到请求的时间相差是否在指定范围内,比如5分钟内)
  2. token验证
  3. ip验证
  4. 来源验证

例如

{

  ‘name‘: 用户名,

  ‘key: 加密的验证key,//(name+secret+timestamp来通过不可逆加密生成)

  ‘timestamp’: 时间戳,//验证timestamp与服务接到请求的时间相差是否在指定范围内,比如5分钟内

}

CORS 几种解决方案

CORS背后的基本思想是使用自定义的HTTP头部允许浏览器和服务器相互了解对方,从而决定请求或响应成功与否.

Access-Control-Allow-Origin:指定授权访问的域
Access-Control-Allow-Methods:授权请求的方法(GET, POST, PUT, DELETE,OPTIONS等)

一:简单的自定义CORSFilter / Interceptor

适合设置单一的(或全部)授权访问域,所有配置都是固定的,特简单。也没根据请求的类型做不同的处理

在web.xml 中添加filter

<filter>

    <filter-name>cros</filter-name>

    <filter-class>cn.ifengkou.test.filter.CORSFilter</filter-class>

</filter>

<filter-mapping>

    <filter-name>cros</filter-name>

     <url-pattern>/*</url-pattern>

</filter-mapping>

新增CORSFilter 类

@Component

public class CORSFilter extends OncePerRequestFilter {

  @Override

  protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)

         throws ServletException, IOException {

      response.addHeader("Access-Control-Allow-Origin", "*");

      response.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");

      response.addHeader("Access-Control-Allow-Headers", "Content-Type");

      response.addHeader("Access-Control-Max-Age", "1800");//30 min

      filterChain.doFilter(request, response);

     }

}

Access-Control-Allow-Origin只能配置 或者一个域名*
比如配置了192.168.56.130,那么只有192.168.56.130 能拿到数据,否则全部报403异常

response.addHeader("Access-Control-Allow-Origin", "http://192.168.56.130");

二:nginx 配置支持Ajax跨域

这里是一个nginx启用COSR的参考配置:来源

#

# Wide-open CORS config for nginx

#

location / {

   if ($request_method = ‘OPTIONS‘) {

     add_header ‘Access-Control-Allow-Origin‘ ‘*‘;

     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-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-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‘;

     }

}

三:支持多域名配置的CORS Filter

因为知道已经有可以用的库可以解决,所以就没重复造轮子了。其实因为懒,看看别人的源码算了。。。

mvnrepository搜索cors-filter,目前也就两个可以用

这两个也都大同小异,因为ebay开源在github上,也有详细的README,那么就以ebay的cors-filter为例

配置

添加依赖包到项目

<dependency>

    <groupId>org.ebaysf.web</groupId>

    <artifactId>cors-filter</artifactId>

    <version>1.0.1</version>

</dependency>

添加配置(具体配置项,还是见项目的README.md吧)

<filter>

      <filter-name>CORS Filter</filter-name>

      <filter-class>org.ebaysf.web.cors.CORSFilter</filter-class>

      <init-param>

         <param-name>cors.allowed.origins</param-name>

         <param-value>http://192.168.56.129,http://192.168.56.130</param-value>

     </init-param>

     <init-param>

          <param-name>cors.allowed.methods</param-name>

         <param-value>GET,POST,HEAD,OPTIONS,PUT</param-value>

     </init-param>

     <init-param>

        <param-name>cors.allowed.headers</param-name>

        <param-value>Content-Type,X-Requested-With,accept,Origin,Access-Control-Request-Method,Access-Control-Request-Headers</param-value>

     </init-param>

 </filter>

 <filter-mapping>

     <filter-name>CORS Filter</filter-name>

     <url-pattern>/*</url-pattern>

</filter-mapping>

总结

    cors在开发WebService、RESTful API 时经常会遇到,在以前可能直接通过jsonp解决,jsonp怎么样就不多说了。 总之,CORS技术规范出来这么久了,如果不考虑IE6 IE7的问题,那么还是积极拥抱CORS吧

    上文三种解决方案,通过搜索引擎均能找到,但估计大部分都是用的第一种最简单的无脑的Cors Filter处理,第二种方案是通过nginx配置的,并不适合所有Web应用。第三种,考虑得很周全,而且使用方便,如果不考虑造重复轮子,推荐使用。

本文转载自路径:http://www.cnblogs.com/sloong/p/cors.html

以上是关于详解 CORS跨域的几种不同实现方式的主要内容,如果未能解决你的问题,请参考以下文章

跨域通信的几种方式

Spring跨域的解决方式

Springboot 配置cors 跨域的几种方法

如何用CORS来解决JS中跨域的问题

js跨域js实现跨域访问的几种方式

跨域的几种方法