spring boot CORS 跨域

 

 

CORS 通俗讲解(结合图里场景:React 前端 + SpringBoot 后端)

1. 先看懂图里场景

  • 前端 React:http://localhost:5173
  • SpringBoot 后端:http://localhost:8080
协议、域名、端口任意一个不一样 → 跨域。
 
浏览器自带安全机制 CORS(跨域资源共享),默认阻止这种请求,控制台直接报红色 CORS 错误。
重点:跨域限制是【浏览器行为】,后端接口本身能收到请求,浏览器拦截了返回结果,不是 SpringBoot 直接拒绝!

2. SpringBoot 最简单三种解决方案(从简单到规范)

方式 1:单个 Controller 快速开启(最简单,测试用)

直接在控制器类上加注解
java
 
运行
 
 
@RestController
@RequestMapping("/api/companies")
@CrossOrigin(origins = "http://localhost:5173") // 允许前端地址跨域
public class CompanyController {

    @GetMapping
    public List<CompanyDTO> getAll(){
        //业务代码
    }
}
 

 

@CrossOrigin 写在类上:当前 Controller 全部接口允许跨域;
 
写在方法上:只单独放开某一个接口。
origins = "*" 代表允许所有前端地址(生产环境不推荐,不安全,仅本地测试)
java
 
运行
 
 
@CrossOrigin(origins = "*")

 

 

方式 2:全局配置(项目正式推荐,所有接口统一生效)

新建一个配置类,一次性全局开启跨域,不用每个 Controller 加注解
java
 
运行
 
 
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class CorsConfig implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**") // 匹配后端所有接口
                .allowedOrigins("http://localhost:5173") //允许的前端域名
                .allowedMethods("GET","POST","PUT","DELETE") //允许请求方式
                .allowCredentials(false);
    }
}
 

 

3. 完整流程演示(发生了什么)

  1. 前端 localhost:5173 axios 请求后端 localhost:8080/api/companies
  2. 浏览器识别:地址不一样 = 跨域
  3. 浏览器自动先发 OPTIONS 预检请求询问后端:允不允许这个前端访问你?
  4. 如果后端配置了 CORS,响应头带上 Access-Control-Allow-Origin
  5. 浏览器看到合法响应头 → 放行,正式发送 GET/POST 请求
  6. 没有配置 CORS → 浏览器直接拦截,报图中的 CORS Policy 错误

4. 重要避坑知识点

  1. ❌ 不要以为后端能收到请求 = 没有跨域
     
    后端代码正常执行,但是浏览器不给前端接收返回数据。
  2. * 不能和 allowCredentials=true(携带 Cookie)同时使用;
  3. 生产环境不要写 *,指定真实前端域名,防止恶意网站调用你的接口。
  4. CORS 只限制浏览器 AJAX/fetch 请求。Postman、后端之间调用接口不受跨域约束!

 

 

 

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

 

这是 全局统一配置跨域方案,不需要在每个 Controller 写@CrossOrigin,企业项目最常用方式。
java
 
运行
 
 
@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/api/**")
                .allowedOrigins("https://domain2.com")
                .allowedMethods("PUT", "DELETE")
                .allowedHeaders("header1", "header2", "header3")
                .exposedHeaders("header1", "header2")
                .allowCredentials(true)
                .maxAge(3600);
    }
}
 

 

每一条方法含义拆解

  1. registry.addMapping("/api/**")
     
    匹配路径规则:只对后端 /api/开头所有接口 启用跨域规则。
     
    如果你写 /** = 后端全部接口生效。
  2. .allowedOrigins("https://domain2.com")
     
    允许哪个前端域名跨域访问后端;
     
    👉 只允许 https://domain2.com,其他前端域名一律拦截。
测试可以写 "*",生产绝对不推荐。
  1. .allowedMethods("PUT", "DELETE")
     
    允许哪些 HTTP 请求方式跨域。
     
    这里仅开放 PUT、DELETE;GET/POST 都会被阻止!
     
    一般项目完整写法:"GET","POST","PUT","DELETE"
  2. .allowedHeaders("header1", "header2", "header3")
     
    允许前端请求携带哪些自定义请求头。
     
    前端如果传了不在列表内的 header,浏览器直接跨域报错。
  3. .exposedHeaders("header1", "header2")
     
    【容易混淆重点】
     
    默认情况下:前端 JS 拿不到后端返回的自定义响应头。
     
    配置这里,代表告诉浏览器:允许前端读取这几个返回头。
  4. .allowCredentials(true)
     
    允许跨域请求携带 Cookie、Session 凭证。
     
    ⚠️ 重要冲突规则:开启 true 之后,allowedOrigins 不能写 * 通配符,必须指定具体域名!
  5. .maxAge(3600)
     
    浏览器预检 OPTIONS 请求缓存时长,单位秒。
     
    3600 = 1 小时:1 小时之内,浏览器不用重复发送 OPTIONS 预检询问后端,优化性能。

@CrossOrigin 注解对比

  1. @CrossOrigin:局部,作用在单个 Controller / 接口,适合临时测试
  2. WebMvcConfigurer + addCorsMappings:全局统一管理
     
    所有接口一套规则,便于维护,正式项目首选。

适配你之前项目的实战改造示例

前端地址:http://localhost:5173,后端接口 /api/**
java
 
运行
 
 
@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/api/**")
                .allowedOrigins("http://localhost:5173")
                .allowedMethods("GET","POST","PUT","DELETE")
                .allowCredentials(false)
                .maxAge(3600);
    }
}

 

 

补充一个坑

如果你项目同时使用 Spring Security,单纯这个配置会失效!
 
Security 有自己的 CORS 校验,需要额外在 Security 配置中开启 cors 支持。

一句话总结幻灯片内容

实现WebMvcConfigurer接口,重写addCorsMappings,可以集中定义一套细粒度跨域策略:限制哪些接口、哪个前端域名、哪些请求方式、请求头允许跨域访问。

 

 

 

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

 

 

先说核心原因(为什么 WebMvc 跨域配置会失效)

Spring Security 的过滤器链 执行顺序早于 SpringMVC 的 CORS 处理
 
请求先进 Security 过滤器 → Security 先校验跨域,如果没放行,直接拒绝请求,根本不会走到 WebMvcConfigurer#addCorsMappings
简单流程:
 
浏览器 OPTIONS 预检请求 → Security 过滤器(优先执行)
 
→ Security 默认没有开启 CORS 支持 → 直接 403 拒绝
 
→ MVC 全局跨域代码永远得不到执行
解决方案:两处任选其一,推荐方案 2(统一管理)
 
1)Security 内部启用 Cors,并且复用 MVC 的跨域配置
 
2)Security 内部直接定义 Cors 配置(不依赖 WebMvc)

二、标准完整配置(你现有代码基础改造)

你已经有这个 MVC 跨域配置:
java
 
运行
 
 
@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/api/**")
                .allowedOrigins("http://localhost:5173")
                .allowedMethods("GET","POST","PUT","DELETE")
                .allowCredentials(false)
                .maxAge(3600);
    }
}
 

 

关键:SpringSecurity 配置里开启 .cors()

java
 
运行
 
 
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
public class SecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
                // ✅ 最重要一行!启用CORS,自动读取上面WebMvc的跨域规则
                .cors()
                .and()
                .csrf().disable() //前后端分离项目一般关闭csrf
                .authorizeHttpRequests(auth -> auth
                        .requestMatchers("/api/public/**").permitAll()
                        .anyRequest().authenticated()
                );

        return http.build();
    }
}

 

 
加上 .cors() 之后,Security 会自动寻找容器中 WebMvcConfigurer 的跨域规则,两者共用一套配置,不用重复写代码。

三、备选方案:完全在 Security 中硬编码 CORS(不依赖 WebMvc)

如果你不想使用 WebMvc 的配置,可以手动提供一个 CorsConfigurationSource Bean:
java
 
运行
 
 
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http
            .cors(cors -> cors.configurationSource(corsConfigurationSource()))
            .csrf().disable()
            .authorizeHttpRequests(auth -> auth.anyRequest().permitAll());
    return http.build();
}

// 单独定义跨域规则
@Bean
public CorsConfigurationSource corsConfigurationSource() {
    CorsConfiguration config = new CorsConfiguration();
    config.setAllowedOrigins(List.of("http://localhost:5173"));
    config.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE"));
    config.setMaxAge(3600L);

    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration("/api/**", config);
    return source;
}
 

 

四、高频踩坑清单

  1. ❌ 只写 WebMvcConfigurer,Security 不加 .cors() → 跨域直接失效
  2. allowCredentials(true) + allowedOrigins("*")
     
    浏览器规范不允许,启动不报错,前端依然跨域失败!必须写明确域名
  3. ❌ 同时多处定义跨域(@CrossOrigin + WebMvc + Security)容易规则冲突,建议统一一套
  4. OPTIONS 预检请求被 Security 拦截:开启.cors()之后框架会自动放行 OPTIONS,不需要手动放行 OPTIONS 接口

五、最简总结

SpringSecurity 过滤器执行优先级高于 SpringMVC,必须在 Security 中显式开启 .cors ();开启后自动复用 WebMvcConfigurer 的跨域规则,一套配置全局生效。
如果你需要,我可以给你一份可以直接复制、前后端分离(React5173 + SpringBoot8080 + Security)完整可运行样板代码。

 

 

 

posted @ 2026-07-30 16:11  漫漫长路</>  阅读(10)  评论(0)    收藏  举报