SpringMVC支持跨域的几种姿势

文章目录
  1. SpringMVC支持跨域的几种姿势
    1. I. Jsonp的支持
      1. 分析说明
    2. II. 支持cors跨域
      1. 1. 背景
      2. 2. 实现方式
        1. a. xml配置方式
        2. b. 注解方式
        3. c. 直接修改返回的responseHeader
    3. III. 小结
    4. IV. 其他
      1. 声明
      2. 扫描关注,java分享

SpringMVC支持跨域的几种姿势

跨域好像是一个前端的问题,通常是a域名下向b域名的服务发起请求,然后处于浏览器的安全原则,被拦截了,而这种场景,在实际的项目中并不少见,那么作为后端可以怎么去支持跨域的case呢?

后端需要支持跨域,一个是支持jsonp请求;还有一个就是设置responseHeader中crossOrigin等相关参数

I. Jsonp的支持

jsonp的请求表现方式就是url里面会多一个参数 callback,一般如下

1
callback=jQuery21105810685605043302_1516257942328

jsonp的返回与一般调用方式的返回也会有点区别,会在外面包装一层,如

1
jQuery21105810685605043302_1516257942328(...);

springmvc中,jsonp的支持却是比较简单了,不需要对现有的接口进行任何处理,只需要像下面这么玩即可

1
2
3
4
5
6
@ControllerAdvice
public class JsonpAdvice extends AbstractJsonpResponseBodyAdvice {
public JsonpAdvice() {
super("callback");
}
}

分析说明

首先是利用了注解 @ControllerAdvice , 这个注解在后面说到的统一异常处理时,也会用到,从命名也可以看出,就是为Controller添加一个切面,简单来讲,就是在直接返回数据前,对返回的结果包装一把;从实现也可以看出,主要的逻辑就在 AbstractJsonpResponseBodyAdvice 里面,所以有必要看一下这个东西是怎么支持的了

核心的代码逻辑就是

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@Override
protected void beforeBodyWriteInternal(MappingJacksonValue bodyContainer, MediaType contentType,
MethodParameter returnType, ServerHttpRequest request, ServerHttpResponse response) {

HttpServletRequest servletRequest = ((ServletServerHttpRequest) request).getServletRequest();

for (String name : this.jsonpQueryParamNames) {
String value = servletRequest.getParameter(name);
if (value != null) {
if (!isValidJsonpQueryParam(value)) {
if (logger.isDebugEnabled()) {
logger.debug("Ignoring invalid jsonp parameter value: " + value);
}
continue;
}

// 下面三行是主要的逻辑
MediaType contentTypeToUse = getContentType(contentType, request, response);
response.getHeaders().setContentType(contentTypeToUse);
bodyContainer.setJsonpFunction(value);
break;
}
}
}

直接看可能看不太明白究竟做了什么,写了个测试,debug下相关的参数如下

IMAGE

即,修改返回的 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
2
3
4
5
<mvc:cors>
<mvc:mapping path="/ajax/*"
allowed-origins="*"
max-age="3600" />
</mvc:cors>

b. 注解方式

在controller方法上,添加下面这个注解即可

1
2
3
4
5
@CrossOrigin(origins = "*")
@RequestMapping(value = {"xx"},
method = {RequestMethod.GET, RequestMethod.POST, RequestMethod.OPTIONS})
public ResponseWrapper<WxBaseResponse> create(HttpServletRequest httpServletRequest) {
}

c. 直接修改返回的responseHeader

1
2
3
response.setHeader("Access-Control-Allow-Origin", request.getHeader("origin"));
response.setHeader("Access-Control-Allow-Methods", "*");
response.setHeader("Access-Control-Allow-Credentials", "true");

III. 小结

上面介绍了两种方式,支持起来都比较简单

  • jsonp: 通过ControllerAdvice拦截Controller,然后继承AbstractJsonpResponseBodyAdvice即可
  • cors: 通过xml配置或者直接使用 @CrossOrigin注解

IV. 其他

声明

尽信书则不如,已上内容,纯属一家之言,因本人能力一般,见解不全,如有问题,欢迎批评指正

扫描关注,java分享

QrCode

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×