失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > 跨域ajax post json 403 跨域请求403详解

跨域ajax post json 403 跨域请求403详解

时间:2019-06-20 16:36:29

相关推荐

跨域ajax post json 403 跨域请求403详解

0、环境说明

1、下文中跨域实现为服务器域名 向本地项目 发起跨域请求,本地进行debug。

2、本地项目 Spring 版本为 4.3.0。

跨域的实现方式有很多种,注解、过滤器、拦截器都能很好的实现跨域的功能,但在实际应用中却发现在同一个跨域实现、同一个 controller 类下,有的跨域请求成功,有的跨域请求返回 403,如图1 所示。

image

1、基于拦截器的跨域403响应

图1所示请求中,采取的是通过过滤器的方式实现跨域,ajax 请求方式为 GET请求,content-type 为 application/json,是一个复杂请求。初始过滤器代码如下:

public class CorsFilter extends OncePerRequestFilter {

@Override

protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {

String originUrl = request.getHeader("origin");

if(!StringUtils.isEmpty(originUrl)){

//自定义跨域域名检查

boolean isAllow = checkAllow(originUrl);

if (isAllow) {

response.setHeader("Access-Control-Allow-Origin", originUrl);

}

response.setHeader("Access-Control-Allow-Credentials", "true");

response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS");

response.setHeader("Access-Control-Max-Age", "1800");//30分钟

response.setHeader("Access-Control-Allow-Headers", "x-requested-with, content-type");

}

filterChain.doFilter(request, response);

}

}

上述拦截器在拦截普通跨域请求时能够正常跨域,但遇到复杂跨域请求时,在发起预请求的时候预请求阶段就返回 403 ,跨域失败,结果如图1所示。

image

如图2所示,该方法的全限定名为 org.springframework.web.cors.DefaultCorsProcessor#processRequest,对于CorsConfiguration对象为空的预请求,将直接返回403,至于CorsConfiguration,可以参考另一篇文章

大致流程为:Spring 容器在启动的时候会扫描每一个添加了 @Controller 注解的类、@RequestMapping注解的方法,之后判断类或者方法上是否有 @CrossOrigin 注解,并将 @CrossOrigin 注解中的内容转换成 CorsConfiguration 对象,具体转换逻辑如图3所示:

image

而对于基于过滤器实现的跨域,没有 @CrossOrigin 注解的加持,CorsConfiguration 对象自然为空,而在Spring对跨域请求的处理逻辑中,对于CorsConfiguration 对象为空的预请求是会执行 rejectRequest 方法,也就是返回状态码 403。既然 Spring 对跨域请求的处理逻辑我们无法改变,所以我们可以在过滤器中添加对 预请求的单独处理或者采用注解的方式解决复杂请求的跨域403响应。修改后的过滤器如下:

public class CorsFilter extends OncePerRequestFilter {

@Override

protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {

String originUrl = request.getHeader("origin");//请求的地址

if(!StringUtils.isEmpty(originUrl)){

//自定义跨域域名检查

boolean isAllow = checkAllow(originUrl);

if (isAllow) {

response.setHeader("Access-Control-Allow-Origin", originUrl);

}

response.setHeader("Access-Control-Allow-Credentials", "true");

response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS");

response.setHeader("Access-Control-Max-Age", "1800");//30分钟

response.setHeader("Access-Control-Allow-Headers", "x-requested-with, content-type");

//对预请求单独处理

String method = request.getMethod();

if (method.equalsIgnoreCase("OPTIONS")){

response.setStatus(HttpServletResponse.SC_OK);

return;

}

}

filterChain.doFilter(request, response);

}

}

2、基于注解的跨域403响应

基于注解的跨域实现能够解决 CorsConfiguration 对象为空的问题,进而解决了在拦截器的实现方式中预请求403的问题。但注解并不能解决所有问题,注解使用不当的时候仍然可能返回403响应。

问题产生场景:

1、方法上的注解未设置 methods 属性

2、ajax请求方法为 POST(或其他非HEAD、GET)方法。

问题产生原因:

image

如图4所示,当方法上的 @CrossOrigin 注解未进行任何配置时,获得的 allowMethods 对象为空导致返回 403 响应。checkMethods方法代码如下:

protected List checkMethods(CorsConfiguration config, HttpMethod requestMethod) {

//方法的具体逻辑见图5

return config.checkHttpMethod(requestMethod);

}

image

由图5可知,当@CrossOrigin 注解未配置 methods 属性时,默认只允许 GET、HEAD 方法的访问,对于其他的请求方法都将返回403响应。

解决办法:

给方法添加跨域注解时增加需要支持的方法,比如:@CrossOrigin(methods = {RequestMethod.GET, RequestMethod.POST})

3、总结

a、使用过滤器、拦截器等的配置方式无法解决复杂请求的预请求的问题,但对于POST方法的简单请求不会出现问题。

b、使用注解的方式在不设置跨域方法的情况下对非 GET、HEAD 方法的请求会出现403的响应,但对于复杂请求无需做额外的逻辑处理。

如果觉得《跨域ajax post json 403 跨域请求403详解》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。