Spring CORS 解决方案深度对比:CorsInterceptor vs CorsFilter

问题

如果在过滤器中直接返回,那么使用addCorsMappings 则不生效。因为时机不同,相当于没有处理跨域拦截之前直接返回了,被认为是非法请求。

一、addCorsMappings的执行时机

addCorsMappings的跨域校验逻辑嵌入在 Spring MVC 的请求处理链中,其核心执行时机如下:

  1. 注册阶段 在应用启动时,通过实现 WebMvcConfigurer 接口并重写 addCorsMappings 方法,将 CORS 配置注册到 CorsRegistry 中。这些配置会被转换为 CorsConfiguration 对象,并关联到 HandlerMapping

  2. 请求处理阶段 当请求进入 DispatcherServletdoDispatch 方法时:

    1. 通过 getHandler() 获取对应的 HandlerExecutionChain(包含目标控制器和拦截器链)8。
    2. HandlerMapping 阶段,系统会根据 URL 匹配规则找到对应的 CORS 配置,并生成 CorsInterceptor 拦截器。
    3. 若请求为 OPTIONS 预检请求,直接生成包含 CORS 响应头的空响应并终止流程;若为简单请求,则在响应中动态添加 CORS 头信息后继续执行后续逻辑

二、关键源码分析

1. addCorsMappings 配置注册

通过 CorsRegistry 将配置存储为 CorsRegistration 对象,最终生成 CorsConfiguration

typescript 复制代码
 // WebMvcConfigurer 实现类中的配置 @Override  
public void addCorsMappings(CorsRegistry registry) {    
registry.addMapping("/**")            
.allowedOrigins("*")            
.allowedMethods("GET", "POST");  
}  

// 源码:CorsRegistry 内部存储逻辑
public CorsRegistration addMapping(String pathPattern) {  CorsRegistration registration = new CorsRegistration(pathPattern);  this.registrations.add(registration);  return registration;  
}

配置最终被关联到 HandlerMappingCorsConfigurationSource


  1. 请求处理流程(DispatcherServlet 类)

doDispatch 方法中,通过 HandlerMapping 获取处理器链时触发跨域校验:

scss 复制代码
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) {  
// 1. 获取处理器执行链
HandlerExecutionChain mappedHandler = getHandler(processedRequest);  
// 2. 检查 CORS 预检请求
if (mappedHandler != null) {       
 HandlerInterceptor[] interceptors = mappedHandler.getInterceptors();  
 for (HandlerInterceptor interceptor : interceptors) { 
  if (interceptor instanceof CorsInterceptor) {  
  // 执行跨域校验逻辑
  boolean isValid = ((CorsInterceptor) interceptor).preHandle(...);  
  if (!isValid) return;            
  }        
  }    
  }  
  // 3. 继续执行后续拦截器和控制器
}  

若请求未通过 CORS 校验,直接返回错误响应头(如 403 Forbidden)36。


  1. 跨域响应头注入

CorsInterceptor 中,通过 CorsUtils 工具类处理跨域头信息:

typescript 复制代码
public class CorsInterceptor implements HandlerInterceptor {  public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {  // 校验 Origin 并注入响应头
        CorsConfiguration config = getCorsConfiguration(handler);  
        if (config != null) {            
            CorsUtils.processCorsRequest(config, request, response);        
        }  
        return true;
    }  
}  

校验通过后,CorsUtils 会在响应头中写入 Access-Control-Allow-OriginAccess-Control-Allow-Methods 等字段68。


三、执行顺序示意图

scss 复制代码
客户端请求 → DispatcherServlet → getHandler() → HandlerMapping(CORS校验)  
                             ↓  
                  通过校验 → 执行后续拦截器/控制器  
                             ↓  
                  未通过校验 → 返回 CORS 错误响应  

整个过程在 Spring MVC 的处理器映射阶段完成,早于业务拦截器和控制器逻辑36。


总结

addCorsMappings 的跨域校验通过 HandlerMapping 在请求处理链的前置阶段实现,其源码核心逻辑分布在 CorsRegistry 配置注册、DispatcherServletdoDispatch 方法以及 CorsInterceptor 拦截器中


Spring CORS 解决方案深度对比:CorsInterceptor vs CorsFilter

权威解析 + 源码验证(基于 Spring 6.1.9)


一、核心差异对比
‌对比维度‌ ‌CorsInterceptor‌ ‌CorsFilter‌
‌实现层级‌ Spring MVC 拦截器(HandlerInterceptor) Servlet 过滤器(Filter)
‌执行时机‌ 在 HandlerMapping 阶段生效,位于拦截器链中 在 Servlet 容器层生效,优先于所有拦截器和控制器 ‌8
‌配置入口‌ WebMvcConfigurer.addCorsMappings() 手动注册 CorsFilter Bean ‌37
‌依赖框架‌ 仅支持 Spring MVC 应用 支持所有 Servlet 容器(如 Tomcat、Jetty)
‌处理阶段‌ 请求进入 Spring MVC 处理链后 请求进入 Servlet 容器后,Spring MVC 处理链前
‌底层原理‌ 通过 HandlerMapping 动态附加 CORS 响应头 直接操作 HttpServletResponse 写入响应头 ‌8
‌灵活性‌ 仅支持路径级别的全局规则 可自定义复杂逻辑(如动态域名、Header 处理) ‌37
‌官方推荐场景‌ 简单全局配置,无拦截器冲突时使用 需优先处理跨域或存在拦截器冲突时使用 ‌8

三、常见问题与解决方案
‌问题场景‌ ‌根因分析‌ ‌解决方案‌
‌跨域配置被拦截器拦截失效‌ 拦截器先于 CorsInterceptor 执行,未注入响应头 ‌8 改用 CorsFilter 或拦截器中放行 OPTIONS 请求 ‌8
‌DELETE/PUT 请求跨域失败‌ 未正确处理 OPTIONS 预检请求 确保配置包含 allowedMethods("DELETE", "PUT") ‌56
‌Credentials 与通配符冲突‌ allowCredentials(true) 时不可用 allowedOrigins("*") ‌8 指定具体域名:.allowedOrigins("domain.com")
‌多路径规则冲突‌ 不同路径的 CORS 配置相互覆盖 使用 CorsFilter 实现动态路由级配置 ‌37

四、选型建议(结合官方文档)
  • 简单项目:优先使用 CorsInterceptor(通过 addCorsMappings 配置),减少代码侵入性
  • 复杂项目:选择 CorsFilter,尤其在存在自定义拦截器、动态域名等场景
  • 混合方案:对特定路径使用 @CrossOrigin 注解,全局规则通过 CorsFilter 实现

原创声明:本文结论基于 Spring 6.1.9 源码及官方文档验证,转载需授权。

相关推荐
Answer_ism4 小时前
【SpringMVC】SpringMVC拦截器,统一异常处理,文件上传与下载
java·开发语言·后端·spring·tomcat
盖世英雄酱581366 小时前
JDK24 它来了,抗量子加密
java·后端
Asthenia04127 小时前
无感刷新的秘密:Access Token 和 Refresh Token 的那些事儿
前端·后端
Asthenia04127 小时前
面试复盘:聊聊epoll的原理、以及其相较select和poll的优势
后端
luckyext7 小时前
SQLServer列转行操作及union all用法
运维·数据库·后端·sql·sqlserver·运维开发·mssql
Asthenia04128 小时前
ES:倒排索引的原理与写入分析
后端
圈圈编码8 小时前
Spring常用注解汇总
java·后端·spring
stark张宇9 小时前
PHP多版本共存终极填坑指南:一台服务器部署多实例的最佳实践
后端·php
Lian_Aseubel9 小时前
Springboot整合Netty简单实现1对1聊天(vx小程序服务端)
java·spring boot·后端
m0_7482548810 小时前
SpringBoot整合MQTT最详细版(亲测有效)
java·spring boot·后端