CORS跨域资源共享(三):@CrossOrigin/CorsFilter处理跨域请求示例及原理分析【享学Spring MVC】(上)

简介: CORS跨域资源共享(三):@CrossOrigin/CorsFilter处理跨域请求示例及原理分析【享学Spring MVC】(上)

前言


通过前两篇文章做好了的铺垫和讲述,现在的你应该了解了CORS是怎么回事以及Spring MVC对它是如何支持的,我有理由相信你现在完全是有能力去解决CORS跨域请求问题,而不用再是两眼一抹黑了。

正所谓好人做到底,送佛送到西,小伙伴一直最为关心Spring MVC对CORS的落地实操示例我还没有给出,当然还有它的处理流程原理分析,那么本文就是你最应该关注和收藏的了。


CORS跨域请求处理方式


针对CORS跨域请求的处理,了解了基础知识后的我们知道,即使没有Spring MVC的支持我们也是能够自行处理的,毕竟在Spring4.2之前都是开发者自己手动向HttpServletResponse设置请求头来解决问题的。

对于新时代的开发者,显然这种硬编码的方式就需要被淘汰el。Spring MVC内置的支持方式有多种,可谓非常多样和灵活。下面就聊聊这些处理方式并给出示例Demo,仅供参考。


方式一:自定义Filter/HandlerInterceptor


前面有说到,Spring直到4.2版本才提供了对CORS的支持,因此对于一些老项目,一般会使用自定义的Filter/拦截器来处理:

// 自定义一个Filter来处理CORS跨域请求
@Component
public class CORSFilter implements Filter {
  @Override
  public void init(FilterConfig filterConfig) throws ServletException {
  }
  // TODO:这里应该是只需要处理OPTIONS请求即可~~~
  @Override
  public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
      HttpServletResponse response = (HttpServletResponse) servletResponse;
      response.setHeader("Access-Control-Allow-Origin", "*");
      response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
      response.setHeader("Access-Control-Max-Age", "3600");
      response.setHeader("Access-Control-Allow-Headers", "content-type,Authorization");
      // response.setHeader("Access-Control-Allow-Credentials", "true");
      filterChain.doFilter(servletRequest, servletResponse);
  }
  @Override
  public void destroy() {
  }
}


方式二:Nginx统一配置

配置在Nginx后,后端服务就不用再操心跨域请求问题了,这是很多公司推荐的方案。

此处我贴出一个配置供以参考,copy自这里


#
# Wide-open CORS config for nginx
#
location / {
  #### 对OPTIONS请求,会设置很多的请求头,并返回204
     if ($request_method = 'OPTIONS') {
        add_header 'Access-Control-Allow-Origin' '*';
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
        #
        # Custom headers and headers various browsers *should* be OK with but aren't
        #
        add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
        #
        # Tell client that this pre-flight info is valid for 20 days
        #
        add_header 'Access-Control-Max-Age' 1728000;
        add_header 'Content-Type' 'text/plain; charset=utf-8';
        add_header 'Content-Length' 0;
        return 204;
     }
     if ($request_method = 'POST') {
        add_header 'Access-Control-Allow-Origin' '*';
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
        add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
        add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
     }
     if ($request_method = 'GET') {
        add_header 'Access-Control-Allow-Origin' '*';
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
        add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
        add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
     }
}


上面是自定义方式解决,不强依赖于Spring MVC框架的支持。那么下面就是使用Spring4.2后提供的能力来灵活解决,这当然也是生厂上主流使用的方案。


方式三:CorsFilter


Spring MVC 4.2后内置了一个CorsFilter专门用于处理CORS请求问题,它所在的路径是:org.springframework.web.filter.CorsFilter。通过配置这个Filter使它生效便可统一控制跨域请求(URL级别控制):


public class MyWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
  ...
  // 使用javax.servlet.ServletContainerInitializer方式注册Filter
    @Override
    protected void registerDispatcherServlet(ServletContext servletContext) {
        super.registerDispatcherServlet(servletContext);
        // 注册Jar包内 内置的Filter等等
        UrlBasedCorsConfigurationSource confiurationSource = new UrlBasedCorsConfigurationSource();
        // 根据URL配置其对应的CORS配置 key支持的是AntPathMatcher.match()
        // 说明:这里请使用LinkedHashMap,确保URL的匹配顺序(/**请放在最后一个)
        Map<String, CorsConfiguration> corsConfigs = new LinkedHashMap<>();
        //corsConfigs.put("*", new CorsConfiguration().applyPermitDefaultValues());
        // '/**'表示匹配所有深度的路径
        corsConfigs.put("/**", new CorsConfiguration().applyPermitDefaultValues());
        confiurationSource.setCorsConfigurations(corsConfigs);
        // /*表示所有请求都用此filter处理一下
        servletContext.addFilter("corsFilter", new CorsFilter(confiurationSource))
                .addMappingForUrlPatterns((EnumSet.of(DispatcherType.REQUEST)), false, "/*");
  }
}


我觉得这个示例的难点反倒是注册这个Jar包内的Filter,若是SpringBoot环境大伙都会注册,但本文示例是全注解驱动的Spring MVC(木有web.xml)环境。关于它的更多注册方式,可参见这里

配置好Filter后,点击发送按钮,即可正常跨域访问了。


image.png


方式四:@CrossOrigin

如果觉得使用CorsFilter配置起来麻烦,或者你想实现精细化且更加简便的控制,那么@CrossOrigin这个注解你值得拥有。

它使用方式极其简单,如下案例:


@CrossOrigin(origins = "http://localhost:63342", methods = {GET, POST, PUT, DELETE}, maxAge = 60L)
@RequestMapping(value = "/test/cors", method = {OPTIONS, GET})
public Object testCors() {
    return "hello cors";
}


这样点击发送便能正常跨域请求了,截图如下:


image.png


难道每个Controller都显示的写上这个注解来处理?当然不是,除了这种局部配置外,Spring MVC还提供了下面这种全局配置的方式


方式五:WebMvcConfigurer方式全局配置

Spring MVC提供的这种配置方法我个人认为是最好的方式,能解决几乎所有问题。从语义配置上能表现出这是web层的东西而非其它,从使用上也非常的简单,因此我个人推荐这种方式而非Filter方式。

@Configuration
@EnableWebMvc
public class WebMvcConfig extends WebMvcConfigurerAdapter {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/test/cors")
            // -------addMapping后还可以继续配置-------
            .allowedOrigins("http://localhost:63342")
            .maxAge(300L);
        registry.addMapping("/**").allowedOrigins("*");
    }
}


等价的xml的方式表达:


<mvc:cors>
  <mvc:mapping path="/test/cors" ... />
    <mvc:mapping path="/**" ... />
</mvc:cors>


点击发送按钮当然也能正常work。截图如下:


image.png


本文我一共总结了5种方式来处理CORS的跨域访问问题,任意一种方式其实都可达到目的。此时你是否有这样一个疑问:若配置了多种方式(特别是Spring MVC内置的方式),生效的优先级顺序是怎样的呢?能够形成互补配置?


为了解答这个疑问,就应该先关注下Spring MVC它对CORS请求的一个处理流程以及配置初始化的过程。





相关文章
|
3月前
|
缓存 NoSQL Java
【Azure Redis 缓存】示例使用 redisson-spring-boot-starter 连接/使用 Azure Redis 服务
【Azure Redis 缓存】示例使用 redisson-spring-boot-starter 连接/使用 Azure Redis 服务
|
12天前
|
开发框架 中间件 Java
如何处理跨域资源共享(CORS)的 OPTIONS 请求?
处理 CORS 的 OPTIONS 请求的关键是正确设置响应头,以告知浏览器是否允许跨域请求以及允许的具体条件。根据所使用的服务器端技术和框架,可以选择相应的方法来实现对 OPTIONS 请求的处理,从而确保跨域资源共享的正常进行。
|
12天前
|
JavaScript 前端开发 API
跨域资源共享(CORS)的工作原理是什么?
跨域资源共享(CORS)通过浏览器和服务器之间的这种交互机制,在保证安全性的前提下,实现了跨域资源的访问,使得不同源的网页能够合法地获取和共享服务器端的资源,为现代Web应用的开发提供了更大的灵活性和扩展性。
|
2月前
|
Java 测试技术 数据库
Spring事务传播机制(最全示例)
在使用Spring框架进行开发时,`service`层的方法通常带有事务。本文详细探讨了Spring事务在多个方法间的传播机制,主要包括7种传播类型:`REQUIRED`、`SUPPORTS`、`MANDATORY`、`REQUIRES_NEW`、`NOT_SUPPORTED`、`NEVER` 和 `NESTED`。通过示例代码和数据库插入测试,逐一展示了每种类型的运作方式。例如,`REQUIRED`表示如果当前存在事务则加入该事务,否则创建新事务;`SUPPORTS`表示如果当前存在事务则加入,否则以非事务方式执行;`MANDATORY`表示必须在现有事务中运行,否则抛出异常;
143 4
Spring事务传播机制(最全示例)
|
1月前
|
安全 前端开发 网络协议
[Http] 跨源资源共享(CORS)
[Http] 跨源资源共享(CORS)
|
2月前
|
安全
CORS 跨域资源共享的实现原理
CORS 跨域资源共享的实现原理
|
4月前
|
安全
CORS 跨域资源共享的实现原理
CORS 跨域资源共享的实现原理
|
3月前
|
安全 开发者 UED
|
3月前
|
JSON 小程序 API
【Azure API 管理】APIM CORS策略设置后,跨域请求成功和失败的Header对比实验
【Azure API 管理】APIM CORS策略设置后,跨域请求成功和失败的Header对比实验
|
4月前
|
缓存 前端开发 Java
在Java项目中实现跨域资源共享(CORS)
在Java项目中实现跨域资源共享(CORS)
下一篇
无影云桌面