Skip to content

Spring Boot 如何处理跨域请求(CORS)? ​

  • 标签:Spring Boot、后端

🏛 业务架构师 ​

Spring Boot 处理 CORS 的方式按作用范围从局部到全局:

1. 全局配置(主流,推荐)——实现 WebMvcConfigurer:

java
@Configuration
public class CorsConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/api/**")
                .allowedOriginPatterns("https://*.mycompany.com")
                .allowedMethods("GET", "POST", "PUT", "DELETE")
                .allowedHeaders("*")
                .allowCredentials(true)
                .maxAge(3600);
    }
}

2. 局部:@CrossOrigin 标在 Controller/方法上(少量接口定制时用)。

3. Filter 方式 / 网关统一处理:CorsFilter 或直接在 Spring Cloud Gateway / Nginx 层全局处理——微服务体系下的首选。

架构师视角,CORS 背后是浏览器安全策略(同源策略下的跨域资源访问授权),我的治理要点:

  1. 网关统一收口:几十个微服务各自配 CORS 必然出错(规则不一致、预检重复处理),统一在网关配置一次,服务零配置——集中治理优于分散治理;
  2. 安全底线:allowCredentials(true) 时严禁 allowedOrigins("*")(规范禁止, cookie 会话下等于放开全站);allowedOrigins 用精确域名或受控模式匹配,"允许所有来源"是数据泄露的起点;
  3. allowCredentials 与自定义 Header:前端带 token/租户头会触发预检(OPTIONS),网关和拦截器要放行预检请求,不然"偶发 403"排查起来非常费时——这是联调阶段的经典时间黑洞。

🏗 系统架构师 ​

四种配置层次(粒度从细到粗):

  1. @CrossOrigin:单 Controller 或方法;
  2. WebMvcConfigurer 的 addCorsMappings:全局路径规则;
  3. CorsFilter/CorsConfigurationSource:Filter 层,执行最早;
  4. 网关统一配置(我的默认选择):SCG 的 globalcors,横切能力上收入口层。
yaml
spring.cloud.gateway.globalcors.cors-configurations:
  '[/**]':
    allowedOriginPatterns: "https://*.example.com"
    allowedMethods: "*"
    allowCredentials: true
    maxAge: 3600

生产要点:

  1. allowCredentials=true 时 origin 禁止通配(规范强制),必须显式白名单(pattern 管理多域名);
  2. 预检(OPTIONS)是性能项:maxAge 缓存预检结果,高频跨域 API 不配会双倍请求量;
  3. CORS 是浏览器安全机制——服务间调用无需也不该配;网关上收后各服务不再散配,避免策略漂移;
  4. 排障:预检 403/405,先查是否被拦截器或安全链拦掉了 OPTIONS。

💻 全栈开发专家 ​

三种层级,按粒度选:

java
// 1. 方法/类级(调试用)
@CrossOrigin(origins = "https://admin.xxx.com")
@GetMapping("/orders")
public Result list() { ... }

// 2. 全局配置(正式项目标准做法)
@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/api/**")
                .allowedOriginPatterns("https://*.xxx.com")
                .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
                .allowedHeaders("*")
                .allowCredentials(true)
                .maxAge(3600);
    }
}
// 3. 微服务首选:网关统一配 globalcors,服务侧不再配

原理一句话:浏览器跨域请求先发 OPTIONS 预检,服务端必须回 Access-Control-Allow-* 头,否则浏览器拦截响应(服务端其实已执行)。

踩坑清单:

  1. allowCredentials(true) 时 allowedOrigins("*") 非法——必须用 allowedOriginPatterns
  2. 预检 OPTIONS 被拦截器/鉴权挡成 401,全站跨域失败;要放行 OPTIONS
  3. 网关配了 CORS、服务又配一遍 → 响应头重复(Access-Control-Allow-Origin 出现两次)浏览器报错——整条链路只允许一处配 CORS,Nginx 和应用重复同理