CORS跨域资源共享(二):详解Spring MVC对CORS支持的相关类和API【享学Spring MVC】(上)

简介: CORS跨域资源共享(二):详解Spring MVC对CORS支持的相关类和API【享学Spring MVC】(上)

前言


上篇文章通过我模拟的跨域请求实例和结果分析,相信小伙伴们都已经80%的掌握了CORS到底是怎么一回事以及如何使用它。由于Java语言中的web框架几乎都是使用的Spring MVC,因此本文将聚焦于Spring MVC对CORS的支持,深度分析下它对CORS支持的相关API,这也方便下一章节的灵活使用以及流程原理分析。


Spring MVC与CORS


Spring MVC一直到4.2版本“才”开始内置对CORS支持,至于为何到这个版本Spring官方才对此提供支持,我这里需要结合时间轴来给大家解释一下。

上文我有说到了CORS它属于W3C的标准。我们知道任何一个规范的形成都是非常漫长的。W3C对web标准的制定分为如下7个阶段(从上到下有序):


  1. WD(Working Draft 工作草案):不稳定也不完整
  2. CR(Candidate Recommendation 候选推荐标准):所有的已知issues都被解决了
  3. PR(Proposed Recommendation 提案推荐标准):在浏览器做各种测试,此部分不会再有实质性的改动
  4. PER(Proposed Edited Recommendation 已修订的提案推荐标准):
  5. REC(Recommendation 推荐标准,通常称之为 standard,即事实标准):几乎不会再变动任何东西
  6. RET(Retired 退役的):最后这两个是建立在REC基础上变来,成熟的技术一般都不会有后面这两个
  7. NOTE(Group Note 工作组说明):


关于这7步,从这里 可以看倒CORS的WD从2009-03-17开始,2014-01-16进入的REC阶段,可谓正式毕业。而Spring4.2是在2015-06发布给与的全面支持,从时间轴上看Spring的响应速度还是把握得不错的(毕竟CORS经历过一段时间市场的考验Spring才敢全面纳入进来支持嘛~)


Tips:在Spring4.2之前,官方没有提供内置的支持,所以那时都是自己使用Filter/拦截器来处理。它的唯一缺点就是可能没那么灵活和优雅,后续官方提供标注支持后能力更强更为灵活了(底层原理都一样)


Spring MVC中CORS相关类及API说明


所有涉及到和CORS相关的类、注解、代码片段都是Spring4.2后才有的,请保持一定的版本意识。


image.png


从截图里可以看出spring-web包提供的专门用于处理CORS的相关的类,下面有必要进行逐个分析

CorsConfiguration


它代表一个cors配置,记录着各种配置项。它还提供了检查给定请求的实际来源、http方法和头的方法供以调用。用人话说:它就是具体封装跨域配置信息的pojo。

默认情况下新创建的CorsConfiguration它是不允许任何跨域请求的,需要你手动去配置,或者调用applyPermitDefaultValues()开启GET、POST、Head的支持~


几乎所有场景,创建完CorsConfiguration最后都调用了applyPermitDefaultValues()方法。也就是说你不干预的情况下,一个CorsConfiguration配置一般都是支持GET、POST、Head的


// @since 4.2
public class CorsConfiguration {
  // public的通配符:代表所有的源、方法、headers...
  // 若你需要使用通配符,可以使用此静态常量
  public static final String ALL = "*";
  private static final List<HttpMethod> DEFAULT_METHODS = Collections.unmodifiableList(Arrays.asList(HttpMethod.GET, HttpMethod.HEAD));
  // 默认许可所有方法
  private static final List<String> DEFAULT_PERMIT_ALL = Collections.unmodifiableList(Arrays.asList(ALL));
  // 默认许可这三个方法
  private static final List<String> DEFAULT_PERMIT_METHODS = Collections.unmodifiableList(Arrays.asList(HttpMethod.GET.name(), HttpMethod.HEAD.name(), HttpMethod.POST.name()));
  // ==========把这些属性对应上文讲述的响应头们对应,和W3C标注都是对应上的=========
  @Nullable
  private List<String> allowedOrigins;
  @Nullable
  private List<String> allowedMethods;
  @Nullable
  private List<HttpMethod> resolvedMethods = DEFAULT_METHODS;
  @Nullable
  private List<String> allowedHeaders;
  @Nullable
  private List<String> allowedHeaders;
  @Nullable
  private List<String> exposedHeaders;
  @Nullable
  private Boolean allowCredentials;
  @Nullable
  private Long maxAge;
  ... // 省略所有构造函数以及所有的get/set方法
  // 使用此方法将初始化模型翻转为以允许get、head和post请求的所有跨源请求的打开默认值开始
  // 注意:此方法不会覆盖前面set进去的值,所以建议此方法可以作为兜底调用。实际上Spring内部也是用它兜底的
  public CorsConfiguration applyPermitDefaultValues() {
    if (this.allowedOrigins == null) {
      this.allowedOrigins = DEFAULT_PERMIT_ALL;
    }
    if (this.allowedMethods == null) {
      this.allowedMethods = DEFAULT_PERMIT_METHODS;
      this.resolvedMethods = DEFAULT_PERMIT_METHODS.stream().map(HttpMethod::resolve).collect(Collectors.toList());
    }
    if (this.allowedHeaders == null) {
      this.allowedHeaders = DEFAULT_PERMIT_ALL;
    }
    if (this.maxAge == null) {
      this.maxAge = 1800L;
    }
    return this;
  }
  public CorsConfiguration combine(@Nullable CorsConfiguration other) { ... }
  // 根据配置的允许来源检查请求的来源
  // 返回值并不是bool值,而是字符串--> 返回可用的origin。若是null表示请求的origin不被支持
  @Nullable
  public String checkOrigin(@Nullable String requestOrigin) { ... }
  // 检查预检请求的Access-Control-Request-Method这个请求头
  public List<HttpMethod> checkHttpMethod(@Nullable HttpMethod requestMethod) { ... }
  // 检查预检请求的Access-Control-Request-Headers
  @Nullable
  public List<String> checkHeaders(@Nullable List<String> requestHeaders) {
}


这个POJO的配置,是servlet传统web以及reactive web所共用的,它提供有校验的基本方法。它的属性、校验原则和W3C的CORS标准所对应。


CorsConfigurationSource


它表示一个源,该接口主要是为请求提供一个CorsConfiguration。


public interface CorsConfigurationSource {
  // 找到此request的一个CORS配置
  @Nullable
  CorsConfiguration getCorsConfiguration(HttpServletRequest request);
}


此接口方法的调用处有三个地方:


  • AbstractHandlerMapping.getHandler()/getCorsConfiguration()
  • CorsFilter.doFilterInternal()
  • HandlerMappingIntrospector.getCorsConfiguration()


因为它可以根据request返回一个CORS配置。可以把这个接口理解为:存储request与跨域配置信息的容器。它的继承树如下:


image.png

首先需要说的便是cors包下的UrlBasedCorsConfigurationSource


UrlBasedCorsConfigurationSource


它位于org.springframework.web.cors包:它里面存储着path patterns和CorsConfiguration的键值对。


// @since 4.2
public class UrlBasedCorsConfigurationSource implements CorsConfigurationSource {
  // 请务必注意:这里使用的是LinkedHashMap
  private final Map<String, CorsConfiguration> corsConfigurations = new LinkedHashMap<>();
  private PathMatcher pathMatcher = new AntPathMatcher();
  private UrlPathHelper urlPathHelper = new UrlPathHelper();
  ... // 生路所有的get/set方法
  // 这里的path匹配用到的是AntPathMatcher.match(),默认是按照ant风格进行匹配的
  @Override
  @Nullable
  public CorsConfiguration getCorsConfiguration(HttpServletRequest request) {
    String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
    for (Map.Entry<String, CorsConfiguration> entry : this.corsConfigurations.entrySet()) {
      if (this.pathMatcher.match(entry.getKey(), lookupPath)) {
        return entry.getValue();
      }
    }
    return null;
  }
}


本类它是作为AbstractHandlerMapping(RequestMappingHandlerMapping)的默认跨域资源配置的管理类

相关文章
|
3月前
|
API 索引
String类下常用API
String类下常用API
44 1
|
3月前
|
安全 Java API
告别繁琐编码,拥抱Java 8新特性:Stream API与Optional类助你高效编程,成就卓越开发者!
【8月更文挑战第29天】Java 8为开发者引入了多项新特性,其中Stream API和Optional类尤其值得关注。Stream API对集合操作进行了高级抽象,支持声明式的数据处理,避免了显式循环代码的编写;而Optional类则作为非空值的容器,有效减少了空指针异常的风险。通过几个实战示例,我们展示了如何利用Stream API进行过滤与转换操作,以及如何借助Optional类安全地处理可能为null的数据,从而使代码更加简洁和健壮。
115 0
|
1月前
|
前端开发 Java 应用服务中间件
【Spring】Spring MVC的项目准备和连接建立
【Spring】Spring MVC的项目准备和连接建立
57 2
|
2月前
|
缓存 前端开发 Java
【Java面试题汇总】Spring,SpringBoot,SpringMVC,Mybatis,JavaWeb篇(2023版)
Soring Boot的起步依赖、启动流程、自动装配、常用的注解、Spring MVC的执行流程、对MVC的理解、RestFull风格、为什么service层要写接口、MyBatis的缓存机制、$和#有什么区别、resultType和resultMap区别、cookie和session的区别是什么?session的工作原理
【Java面试题汇总】Spring,SpringBoot,SpringMVC,Mybatis,JavaWeb篇(2023版)
|
1月前
|
XML 前端开发 Java
Spring,SpringBoot和SpringMVC的关系以及区别 —— 超准确,可当面试题!!!也可供零基础学习
本文阐述了Spring、Spring Boot和Spring MVC的关系与区别,指出Spring是一个轻量级、一站式、模块化的应用程序开发框架,Spring MVC是Spring的一个子框架,专注于Web应用和网络接口开发,而Spring Boot则是对Spring的封装,用于简化Spring应用的开发。
126 0
Spring,SpringBoot和SpringMVC的关系以及区别 —— 超准确,可当面试题!!!也可供零基础学习
|
1月前
|
API
使用`System.Net.WebClient`类发送HTTP请求来调用阿里云短信API
使用`System.Net.WebClient`类发送HTTP请求来调用阿里云短信API
27 0
|
3月前
|
Java 数据库连接 Spring
后端框架入门超详细 三部曲 Spring 、SpringMVC、Mybatis、SSM框架整合案例 【爆肝整理五万字】
文章是关于Spring、SpringMVC、Mybatis三个后端框架的超详细入门教程,包括基础知识讲解、代码案例及SSM框架整合的实战应用,旨在帮助读者全面理解并掌握这些框架的使用。
后端框架入门超详细 三部曲 Spring 、SpringMVC、Mybatis、SSM框架整合案例 【爆肝整理五万字】
|
2月前
|
Java API 开发者
【Java字节码操控新篇章】JDK 22类文件API预览:解锁Java底层的无限可能!
【9月更文挑战第6天】JDK 22的类文件API为Java开发者们打开了一扇通往Java底层世界的大门。通过这个API,我们可以更加深入地理解Java程序的工作原理,实现更加灵活和强大的功能。虽然目前它还处于预览版阶段,但我们已经可以预见其在未来Java开发中的重要地位。让我们共同期待Java字节码操控新篇章的到来!
|
2月前
|
Java API 开发者
【Java字节码的掌控者】JDK 22类文件API:解锁Java深层次的奥秘,赋能开发者无限可能!
【9月更文挑战第8天】JDK 22类文件API的引入,为Java开发者们打开了一扇通往Java字节码操控新世界的大门。通过这个API,我们可以更加深入地理解Java程序的底层行为,实现更加高效、可靠和创新的Java应用。虽然目前它还处于预览版阶段,但我们已经可以预见其在未来Java开发中的重要地位。让我们共同期待Java字节码操控新篇章的到来,并积极探索类文件API带来的无限可能!
|
3月前
|
Java 索引
下一篇
无影云桌面