SpringMVC支持跨域的几种姿势
跨域好像是一个前端的问题,通常是a域名下向b域名的服务发起请求,然后处于浏览器的安全原则,被拦截了,而这种场景,在实际的项目中并不少见,那么作为后端可以怎么去支持跨域的case呢?
后端需要支持跨域,一个是支持jsonp请求;还有一个就是设置responseHeader中crossOrigin等相关参数
I. Jsonp的支持
jsonp的请求表现方式就是url里面会多一个参数 callback,一般如下
1 | callback=jQuery21105810685605043302_1516257942328 |
jsonp的返回与一般调用方式的返回也会有点区别,会在外面包装一层,如
1 | jQuery21105810685605043302_1516257942328(...); |
springmvc中,jsonp的支持却是比较简单了,不需要对现有的接口进行任何处理,只需要像下面这么玩即可
1 | @ControllerAdvice |
分析说明
首先是利用了注解 @ControllerAdvice
, 这个注解在后面说到的统一异常处理时,也会用到,从命名也可以看出,就是为Controller添加一个切面,简单来讲,就是在直接返回数据前,对返回的结果包装一把;从实现也可以看出,主要的逻辑就在 AbstractJsonpResponseBodyAdvice
里面,所以有必要看一下这个东西是怎么支持的了
核心的代码逻辑就是
1 | @Override |
直接看可能看不太明白究竟做了什么,写了个测试,debug下相关的参数如下
即,修改返回的 content-type 为: application/javascript
返回的Container里面设置了jsonpFunction,为请求参数的value,至于是在什么时候封装的返回结果呢?这个有待后续补全
II. 支持cors跨域
Cross-Origin Resource Sharing(CORS)跨来源资源共享是一份浏览器技术的规范,提供了 Web 服务从不同域传来沙盒脚本的方法,以避开浏览器的同源策略,是 JSONP 模式的现代版。与 JSONP 不同,CORS 除了 GET 要求方法以外也支持其他的 HTTP 要求
1. 背景
CORS背后的基本思想是使用自定义的HTTP头部允许浏览器和服务器相互了解对方,从而决定请求或响应成功与否
所以问题就来了,安全如何保证?
一般而言,为了避免夸站点攻击(csrf),常见的手段无非:
- 身份校验(比如要求用户登录)
- token验证
- ip白名单
- 来源referer校验
- 频率限制
2. 实现方式
要支持csrf,也比较简单了,无非就是设置下responseHeader了, 一般需要设置以下几项
- Access-Control-Allow-Origin: *; // 允许的来源
- Access-Control-Allow-Methods: GET, POST, PUT, DELETE
- Access-Control-Allow-Credentials: true
- Access-Control-Allow-Headers: Content-Type
- Access-Control-Max-Age: 1800 //30 min
所以实现起来的方式就比较多了,一个是新增一个filter,主动设置下返回头,当然spring mvc提供了更友好的方式了
常见的几种手段如下:
a. xml配置方式
1 | <mvc:cors> |
b. 注解方式
在controller方法上,添加下面这个注解即可
1 | @CrossOrigin(origins = "*") |
c. 直接修改返回的responseHeader
1 | response.setHeader("Access-Control-Allow-Origin", request.getHeader("origin")); |
III. 小结
上面介绍了两种方式,支持起来都比较简单
- jsonp: 通过ControllerAdvice拦截Controller,然后继承AbstractJsonpResponseBodyAdvice即可
- cors: 通过xml配置或者直接使用 @CrossOrigin注解
IV. 其他
声明
尽信书则不如,已上内容,纯属一家之言,因本人能力一般,见解不全,如有问题,欢迎批评指正