CORS’s source, principle and implementation

CORS(Cross-Origin Resource Sharing)是一种跨域访问技术,是一种 AJAX 跨域请求资源的方式,支持现代浏览器,IE支持10以上。
CORS与JSONP的使用目的相同,但是比JSONP更强大。JSONP只支持GET请求,CORS支持所有类型的HTTP请求。它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。只要服务器实现了CORS接口,就可以跨源通信。

一、source来源

就CORS而言,使用它的根本原因就是要完成资源的跨域访问,也就是如何绕过Same-origin Policy。

那么什么是Same-origin Policy呢?简单地说,在一个浏览器中访问的网站不能访问另一个网站中的数据,除非这两个网站具有相同的Origin,也即是拥有相同的协议、主机地址以及端口。一旦这三项数据中有一项不同,那么该资源就将被认为是从不同的Origin得来的,进而不被允许访问。

但是这个限制的确过于严格了:一个大型网站常常拥有一系列子域。在这些域之间交换数据就会受到Same-origin Policy的限制为了绕过该限制,业界提出了一系列解决该问题的方法,例如更改document.domain属性,跨文档消息,JSONP以及CORS等。这些解决方案各有各的长处,因此我们需要根据需求的不同来对这些方案进行选择。而相较于这些方法,CORS则没有那么多工作需要去做,也没有那么多限制。

二、principle原则

CORS 做到了两点:

  1. 不破坏即有规则
  2. 服务器实现了 CORS 接口,就可以跨源通信

基于这两点, CORS 将请求分为两类:简单请求和非简单请求。

2.1 简单请求

可以先看下 CORS 出现前的情况:跨源时能够通过 script 或者 image 标签触发 GET 请求或通过表单发送一条 POST 请求,但这两种请求 HTTP 头信息中都不能包含任何自定义字段。

简单请求对应该规则,因此对简单请求的定义为:

请求方法是 HEAD、GET 或 POST 且 HTTP 头信息不超过以下几个字段:Accept、Accept-Language、Content-Language、Last-Event-ID、Content-Type(只限于 application/x-www-form-urlencoded、multipart/form-data、text/plain)。

比如有一个简单请求:

1 GET /test HTTP/1.1
2 Accept: */*
3 Accept-Encoding: gzip, deflate, sdch, br
4 Origin: http://www.examples.com
5 Host: www.examples.com

对于这样的简单请求,CORS 的策略是请求时,**在头信息中添加一个 Origin 字段**,服务器收到请求后,根据该字段判断是否允许该请求。

  1. 如果允许,则在 HTTP 头信息中添加 Access-Control-Allow-Origin 字段,并返回正确的结果
  2. 如果不允许,则不在头信息中添加 Access-Control-Allow-Origin 字段。

浏览器先于用户得到返回结果,根据有无 Access-Control-Allow-Origin 字段来决定是否拦截该返回结果。

对于 CORS 出现前的一些服务,CORS 对他们的影响分两种情况:

  1. script 或者 image 触发的 GET 请求不包含 Origin 头,所以不受到 CORS 的限制,依旧可用。
  2. 如果是 ajax 请求,HTTP 头信息中会包含 Origin 字段,由于服务器没有做任何配置,所以返回结果不会包含 Access-Control-Allow-Origin,因此返回结果会被浏览器拦截,接口依旧不可以被 ajax 跨源访问。

可以看出,CORS 的出现,没有对”旧的“服务造成任何影响。

另外,除了提到的 Access-Control-Allow-Origin 还有几个字段用于描述 CORS 返回结果:

  1. Access-Control-Allow-Credentials: 可选,用户是否可以发送、处理 cookie。
  2. Access-Control-Expose-Headers:可选,可以让用户拿到的字段。有几个字段无论设置与否都可以拿到的,包括:Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma。

2.2 非简单请求

除了简单请求之外的请求,就是非简单请求。

对于非简单请求的跨源请求,**浏览器会在真实请求发出前**,增加一次 OPTION 请求,称为预检请求(preflight request)。预检请求将真实请求的信息,包括请求方法、自定义头字段、源信息添加到 HTTP 头信息字段中,询问服务器是否允许这样的操作。

比如对于 DELETE 请求:

1 OPTIONS /test HTTP/1.1
2 Origin: http://www.examples.com
3 Access-Control-Request-Method: DELETE
4 Access-Control-Request-Headers: X-Custom-Header
5 Host: www.examples.com

与 CORS 相关的字段有:

  1. Access-Control-Request-Method: 真实请求使用的 HTTP 方法。
  2. Access-Control-Request-Headers: 真实请求中包含的自定义头字段。

服务器收到请求时,需要分别对 Origin、Access-Control-Request-Method、Access-Control-Request-Headers 进行验证,验证通过后,会在返回 Http 头信息中添加

1 Access-Control-Allow-Origin: http://www.examples.com
2 Access-Control-Allow-Methods: GET, POST, PUT, DELETE
3 Access-Control-Allow-Headers: X-Custom-Header
4 Access-Control-Allow-Credentials: true
5 Access-Control-Max-Age: 1728000

他们的含义分别是:

  1. Access-Control-Allow-Methods: 真实请求允许的方法
  2. Access-Control-Allow-Headers: 服务器允许使用的字段
  3. Access-Control-Allow-Credentials: 是否允许用户发送、处理 cookie
  4. Access-Control-Max-Age: 预检请求的有效期,单位为秒。有效期内,不会重复发送预检请求

当预检请求通过后,浏览器会发送真实请求到服务器。这就实现了跨源请求。

三、implementation实现

CORS实现方式:

3.1 在方法上使用注解 @CrossOrigin(origins="http://ip:port")[注:origins是springmvc4.2以后增加的]

  

3.2 写一个类继承WebMvcConfigurerAdapter类

 

3.3 和方式二类似,全局设置

前端则可以正常调用,eg:

原文地址:https://www.cnblogs.com/vision-xixi/p/11064424.html