同源策略
现在普遍前后端分离,前端 http://ip:port/context 后端http://ip:anotherport/anothercontext ,然后你发现浏览器提示跨域了。或者你是前端或者后端。你们ip不一样,端口一样 ,前端调用后端接口依然提示跨域了。是不是很郁闷?这个跨域是什么玩意儿呢?简单来说如果两个页面的协议,端口(如果有指定)和主机都相同,则两个页面具有相同的源 。
这张图 会让你明白什么时候是同源,什么时候不同源,不同源如果要进行交互就需要跨域。至于为什么要限制,浏览器策略说是为了安全限制,具体原因可以去MDN 了解。本文不讨论。我们只讨论如何跨域。
跨域的方式
JSONP 在HTML标签里,一些标签比如script、img这样的获取资源的src标签是没有跨域限制的,利用这一点。但是现在都9102年了,这种基本不使用了,除非老项目。而且获取资源只能使用GET请求。
空的iframe加上 form表单 iframe 也是带src 的 但是 iframe 中可以放一个form ,form当然可以指定为POST,用后即焚。解决了JSONP不能使用POST的问题。但是也很别扭。
CORS CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)。看名字就知道这是处理跨域问题的标准做法。CORS有两种请求:
a.简单请求
(1) 请求方法是以下三种方法之一:
(2)HTTP的头信息不超出以下几种字段:
b.非简单请求
非简单请求会发出一次预检测请求,返回码是204,预检测通过才会真正发出请求,这才返回200。这里通过前端发请求的时候增加一个额外的headers来触发非简单请求。额外的请求头参数有
Access-Control-Allow-Origin 标识允许哪个域的请求。当然,如果服务器不通过,根本没有这个字段,接着触发XHR的onerror,再接着你就看到浏览器的提示xxx的服务器没有响应Access-Control-Allow-Origin字段。设置*是最简单的,出于安全考虑,肯定不会这么干,而且,如果是*的话,游览器将不会发送cookies,即使你的XHR设置了withCredentials,网上很多教程这么干。
Access-Control-Allow-Credentials 设置布尔值,表示XHR是否接收cookies和发送cookies,也就是说如果该值是false,响应头的Set-Cookie,浏览器也不会理,并且即使有目标站点的cookies,浏览器也不会发送。
Access-Control-Request-Method 跨域请求满足服务器要求的所有请求方式,GET、POST、PUT等
Access-Control-Request-Headers 跨域请求的自定义请求头字段,不限定本次请求一次性告诉服务端。
spring mvc中的cors跨域
以上就是跨域方式的简单介绍,这里我们着重介绍cors这种现代的操作方式,以及在spring mvc中如何设置cors。
使用@CrossOrigin注解 这种最为简单。该注解的属性值跟上面的非简单请求需要的的header参数一一对应,也可以不设置。使用起来也最简单,就像下面的操作:
上面是方法级别的控制粒度。在上面的示例中,CORS仅对canCors()方法启用。如果该控制器下所有的方法都要跨域,而且我们也可以指定一些参数。
这样CorsApi下所有的方法都将支持从 https://api.com 的跨域操作。使用@CrossOrigin的方式虽然简单。但是我们不可能不厌其烦的进行这种操作。如果我们能指定一些通配符方式的来指定那些操作可以cors就好了,当然有下面我们来看看全局配置。
WebMvcConfigurer 是我们的老朋友了,什么过滤器,格式化器,各种视图转换器,各种处理器都是它来注册的,就是一个Spring mvc 的配置中心。通过Ant风格的路径和Cors参数配置我们就可以全局来使用了不再需要注解支持。这种是javaConfig的玩法。如果是老式SSM 那种xml方式该这样玩
简单原理流程
通过 注解或者全局配置的CORS请求会被自动分发到各种已经注册的HandlerMappings(spring mvc 概念),然后由跨域处理器 CorsProcessor 接口(默认实现为DefaultCorsProcessor)来处理CORS预检请求(注意前面非简单的CORS请求介绍),然后拦截器CorsFilter拦截实际的具体请求,添加相关的CORS Headers (例如Access-Control-Allow-Origin),从而实现跨域请求。
总结
我们从跨域的概念到多种cors跨域方式的简单介绍,后面重点介绍了springmvc中CORS的注解方式,全局方式(包括javaConfig方式和xml方式),也讲述了简单的原理流程。相信对于目前前后端分离开发方式还是非常有指导意义的。