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月前
|
负载均衡 Java API
基于 Spring Cloud 的微服务架构分析
Spring Cloud 是一个基于 Spring Boot 的微服务框架,提供全套分布式系统解决方案。它整合了 Netflix、Zookeeper 等成熟技术,通过简化配置和开发流程,支持服务发现(Eureka)、负载均衡(Ribbon)、断路器(Hystrix)、API网关(Zuul)、配置管理(Config)等功能。此外,Spring Cloud 还兼容 Nacos、Consul、Etcd 等注册中心,满足不同场景需求。其核心组件如 Feign 和 Stream,进一步增强了服务调用与消息处理能力,为开发者提供了一站式微服务开发工具包。
469 0
|
5月前
|
SQL 前端开发 Java
深入分析 Spring Boot 项目开发中的常见问题与解决方案
本文深入分析了Spring Boot项目开发中的常见问题与解决方案,涵盖视图路径冲突(Circular View Path)、ECharts图表数据异常及SQL唯一约束冲突等典型场景。通过实际案例剖析问题成因,并提供具体解决方法,如优化视图解析器配置、改进数据查询逻辑以及合理使用外键约束。同时复习了Spring MVC视图解析原理与数据库完整性知识,强调细节处理和数据验证的重要性,为开发者提供实用参考。
239 0
|
9月前
|
XML Java 数据格式
Spring Core核心类库的功能与应用实践分析
【12月更文挑战第1天】大家好,今天我们来聊聊Spring Core这个强大的核心类库。Spring Core作为Spring框架的基础,提供了控制反转(IOC)和依赖注入(DI)等核心功能,以及企业级功能,如JNDI和定时任务等。通过本文,我们将从概述、功能点、背景、业务点、底层原理等多个方面深入剖析Spring Core,并通过多个Java示例展示其应用实践,同时指出对应实践的优缺点。
139 14
|
11月前
|
Java BI API
spring boot 整合 itextpdf 导出 PDF,写入大文本,写入HTML代码,分析当下导出PDF的几个工具
这篇文章介绍了如何在Spring Boot项目中整合iTextPDF库来导出PDF文件,包括写入大文本和HTML代码,并分析了几种常用的Java PDF导出工具。
2415 0
spring boot 整合 itextpdf 导出 PDF,写入大文本,写入HTML代码,分析当下导出PDF的几个工具
|
9月前
|
安全 Java API
实现跨域请求:Spring Boot后端的解决方案
本文介绍了在Spring Boot中处理跨域请求的三种方法:使用`@CrossOrigin`注解、全局配置以及自定义过滤器。每种方法都适用于不同的场景和需求,帮助开发者灵活地解决跨域问题,确保前后端交互顺畅与安全。
1071 0
|
11月前
|
XML Java 应用服务中间件
【Spring】运行Spring Boot项目,请求响应流程分析以及404和500报错
【Spring】运行Spring Boot项目,请求响应流程分析以及404和500报错
949 2
|
12月前
|
设计模式 Java Spring
spring源码设计模式分析(五)-策略模式
spring源码设计模式分析(五)-策略模式
|
12月前
|
消息中间件 设计模式 缓存
spring源码设计模式分析(四)-观察者模式
spring源码设计模式分析(四)-观察者模式
|
12月前
|
设计模式 Java Spring
spring源码设计模式分析(六)-模板方法模式
spring源码设计模式分析(六)-模板方法模式
|
12月前
|
负载均衡 Java 网络架构
实现微服务网关:Zuul与Spring Cloud Gateway的比较分析
实现微服务网关:Zuul与Spring Cloud Gateway的比较分析
644 5