美文网首页
跨域请求403详解

跨域请求403详解

作者: 愤怒的红蓝色 | 来源:发表于2019-07-15 17:17 被阅读0次

0、环境说明

1、下文中跨域实现为服务器域名 http://yaogy.jd.com 向本地项目 leo.com 发起跨域请求,本地进行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,可以参考另一篇文章

Tnlj:CORS与@CrossOrigin详解​zhuanlan.zhihu.com

大致流程为: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<HttpMethod> 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的响应,但对于复杂请求无需做额外的逻辑处理。

知乎链接:跨域请求403 - 知乎

相关文章

  • 跨域请求403详解

    0、环境说明 1、下文中跨域实现为服务器域名 http://yaogy.jd.com 向本地项目 leo.com ...

  • nginx配置跨域请求

    转载 Nginx配置跨域请求 Access-Control-Allow-Origin 当出现403跨域错误的时候 ...

  • 跨域问题详解分析

    参考文档 CORS详解 跨域资源共享 CORS 详解 js中几种实用的跨域方法原理详解 跨域的那些事儿 跨域与跨域...

  • 配置webpack解决前端跨域

    本地请求服务器接口,报403错误,其实是跨域问题。在webpack中有很方便的方式解决跨域问题——webpack的...

  • AJAX出现两次请求 options和get|post

    跨域请求 允许跨域请求 preflighted request预请求(options) 跨域请求 XMLHttpR...

  • Spring Boot跨域

    前后端分离时候势必会遇到Ajax跨域请求。 1. 关于跨域 参考跨域资源共享 CORS 详解 CORS是一个W3C...

  • axios发送俩次请求的原因

    其实跨域分为简单跨域请求和复杂跨域请求 简单跨域请求是不会发送options请求的 复杂跨域请求会发送一个预检请求...

  • 详解 JSONP跨域请求的实现

    详解 JSONP跨域请求的实现[https://www.cnblogs.com/zhaosq/p/10511633...

  • spring boot 跨域问题

    网页端跨域请求403错误! 使用@CrossOrigin 注解 这个大家都知道 但是 必须保证Springmvc版...

  • 用express实现CORS跨域

    跨域请求头 cors express 跨域请求

网友评论

      本文标题:跨域请求403详解

      本文链接:https://www.haomeiwen.com/subject/wgqokctx.html