SpringBoot中处理跨域请求CORS的全面指南

 更新时间:2025年04月08日 09:01:31   作者:北辰alk  
跨域资源共享是一种安全机制,它允许Web应用程序在一个域上的资源请求另一个域上的资源,下面就跟随小编一起来深入了解下SpringBoot中处理跨域请求CORS的具体操作吧

一、CORS基础概念

1.1 什么是跨域请求

跨域资源共享(Cross-Origin Resource Sharing, CORS)是一种安全机制,它允许Web应用程序在一个域上的资源请求另一个域上的资源。浏览器出于安全考虑,会阻止不同源之间的AJAX请求,这是**同源策略(Same-Origin Policy)**的限制。

1.2 同源策略定义

两个URL被认为是同源的条件:

  • 协议相同(http/https)
  • 域名相同
  • 端口相同

例如:

  • http://example.com/app1 和 http://example.com/app2 → 同源
  • http://example.com 和 https://example.com → 不同源(协议不同)
  • http://example.com 和 http://api.example.com → 不同源(域名不同)
  • http://example.com 和 http://example.com:8080 → 不同源(端口不同)

二、Spring Boot处理CORS的5种方式

2.1 全局配置(推荐)

方式1:使用WebMvcConfigurer接口

@Configuration
public class CorsConfig implements WebMvcConfigurer {
    
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")  // 所有接口
                .allowedOrigins("*")  // 允许所有源
                .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")  // 允许方法
                .allowedHeaders("*")  // 允许所有头
                .allowCredentials(true)  // 允许凭证
                .maxAge(3600);  // 预检请求缓存时间
    }
}

方式2:使用Filter方式(适用于Servlet应用)

@Bean
public CorsFilter corsFilter() {
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    CorsConfiguration config = new CorsConfiguration();
    
    config.setAllowCredentials(true);
    config.addAllowedOrigin("*");
    config.addAllowedHeader("*");
    config.addAllowedMethod("*");
    source.registerCorsConfiguration("/**", config);
    
    return new CorsFilter(source);
}

2.2 控制器方法级配置

方式3:使用@CrossOrigin注解

@RestController
@RequestMapping("/api")
public class UserController {
    
    // 单个方法配置
    @CrossOrigin(origins = "http://localhost:3000")
    @GetMapping("/users")
    public List<User> getUsers() {
        // ...
    }
    
    // 整个控制器配置
    @CrossOrigin(origins = "*", maxAge = 3600)
    @RestController
    @RequestMapping("/products")
    public class ProductController {
        // ...
    }
}

2.3 属性文件配置(Spring Boot 2.4+)

方式4:application.yml配置

spring:
  mvc:
    cors:
      allowed-origins: "http://localhost:3000, https://example.com"
      allowed-methods: "GET, POST, PUT, DELETE"
      allowed-headers: "*"
      exposed-headers: "Authorization, Content-Disposition"
      allow-credentials: true
      max-age: 1800

等效的application.properties:

spring.mvc.cors.allowed-origins=http://localhost:3000, https://example.com
spring.mvc.cors.allowed-methods=GET, POST, PUT, DELETE
spring.mvc.cors.allowed-headers=*
spring.mvc.cors.exposed-headers=Authorization, Content-Disposition
spring.mvc.cors.allow-credentials=true
spring.mvc.cors.max-age=1800

2.4 响应头手动设置

方式5:手动添加响应头(灵活但繁琐)

@RestController
public class ApiController {
    
    @GetMapping("/manual")
    public ResponseEntity<String> manualCors() {
        return ResponseEntity.ok()
                .header("Access-Control-Allow-Origin", "*")
                .header("Access-Control-Allow-Methods", "GET")
                .body("Manual CORS configured");
    }
}

三、CORS处理深度解析

3.1 预检请求(Preflight Request)

对于"非简单请求",浏览器会先发送OPTIONS预检请求:

简单请求条件:

1.使用GET、HEAD或POST方法

2.仅包含以下头:

  • Accept
  • Accept-Language
  • Content-Language
  • Content-Type (仅限 application/x-www-form-urlencoded, multipart/form-data, text/plain)

非简单请求示例:

fetch('http://api.example.com/data', {
  method: 'PUT',
  headers: {
    'Content-Type': 'application/json',
    'X-Custom-Header': 'value'
  },
  body: JSON.stringify({key: 'value'})
});

Spring Boot会自动处理OPTIONS请求,无需开发者额外编码。

3.2 核心响应头说明

响应头说明
Access-Control-Allow-Origin允许访问的源,*表示任何源
Access-Control-Allow-Methods允许的HTTP方法
Access-Control-Allow-Headers允许的请求头
Access-Control-Expose-Headers允许浏览器访问的响应头
Access-Control-Allow-Credentials是否允许发送Cookie和HTTP认证信息
Access-Control-Max-Age预检请求结果的缓存时间(秒)

3.3 常见问题解决方案

问题1:allowCredentials(true)与allowedOrigins("*")冲突

错误:

When allowCredentials is true, allowedOrigins cannot contain the special value "*"

解决方案:

// 替换为具体域名
.allowedOrigins("http://localhost:3000", "https://example.com")

问题2:前端仍然报CORS错误

检查步骤:

  • 确保后端已正确配置
  • 检查浏览器控制台错误详情
  • 使用Postman等工具验证接口是否正常工作
  • 检查是否有多个CORS配置相互覆盖

问题3:自定义过滤器干扰CORS

解决方案:

确保CorsFilter在过滤器链中的优先级:

@Bean
public FilterRegistrationBean<CorsFilter> corsFilterRegistration() {
    FilterRegistrationBean<CorsFilter> registration = new FilterRegistrationBean<>();
    registration.setFilter(corsFilter());
    registration.setOrder(Ordered.HIGHEST_PRECEDENCE);  // 最高优先级
    return registration;
}

四、安全最佳实践

4.1 生产环境配置建议

@Configuration
public class ProdCorsConfig implements WebMvcConfigurer {
    
    @Value("${app.cors.allowed-origins}")
    private String[] allowedOrigins;
    
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/api/**")
                .allowedOrigins(allowedOrigins)
                .allowedMethods("GET", "POST")
                .allowedHeaders("Content-Type", "Authorization")
                .exposeHeaders("X-Custom-Header")
                .allowCredentials(true)
                .maxAge(3600);
    }
}

4.2 结合Spring Security

当使用Spring Security时,需要确保CORS配置在安全过滤器之前:

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.cors().and()  // 启用Spring Security的CORS支持
            .csrf().disable()
            .authorizeRequests()
            // 其他配置...
    }
    
    @Bean
    CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(Arrays.asList("https://trusted.com"));
        configuration.setAllowedMethods(Arrays.asList("GET", "POST"));
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }
}

4.3 监控与日志

添加CORS请求日志:

@Bean
public FilterRegistrationBean<CorsFilter> corsFilter() {
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    // ...配置
    
    FilterRegistrationBean<CorsFilter> registration = new FilterRegistrationBean<>();
    registration.setFilter(new CorsFilter(source) {
        @Override
        protected void doFilterInternal(HttpServletRequest request, 
            HttpServletResponse response, FilterChain filterChain) 
            throws ServletException, IOException {
            
            log.info("CORS请求: {} {}", request.getMethod(), request.getRequestURI());
            super.doFilterInternal(request, response, filterChain);
        }
    });
    return registration;
}

五、测试与验证

5.1 测试类示例

@SpringBootTest
@AutoConfigureMockMvc
public class CorsTest {
    
    @Autowired
    private MockMvc mockMvc;
    
    @Test
    public void testCorsHeaders() throws Exception {
        mockMvc.perform(options("/api/users")
                .header("Access-Control-Request-Method", "GET")
                .header("Origin", "http://localhost:3000"))
                .andExpect(header().exists("Access-Control-Allow-Origin"))
                .andExpect(header().string("Access-Control-Allow-Methods", "GET"));
    }
    
    @Test
    public void testActualRequest() throws Exception {
        mockMvc.perform(get("/api/users")
                .header("Origin", "http://localhost:3000"))
                .andExpect(status().isOk())
                .andExpect(header().string("Access-Control-Allow-Origin", "http://localhost:3000"));
    }
}

5.2 使用CURL测试

检查OPTIONS预检请求:

curl -X OPTIONS http://localhost:8080/api/users \
-H "Origin: http://test.com" \
-H "Access-Control-Request-Method: GET" \
-I

检查实际请求:

curl -X GET http://localhost:8080/api/users \
-H "Origin: http://test.com" \
-I

六、总结与推荐方案

6.1 配置方式对比

方式适用场景优点缺点
全局WebMvcConfigurer大多数应用集中管理,支持细粒度配置需要代码变更
过滤器方式需要最高优先级处理处理最早,避免被其他过滤器干扰配置稍复杂
@CrossOrigin注解特定接口需要特殊规则精准控制分散在各处,维护成本高
属性文件配置简单需求,配置驱动无需代码变更灵活性较低
手动设置响应头需要动态决定CORS头最大灵活性代码侵入性强

6.2 推荐方案

新项目:

  • 使用WebMvcConfigurer全局配置
  • 结合属性文件动态配置允许的源
  • 对特殊接口使用@CrossOrigin覆盖全局设置

已有项目迁移:

  • 先添加全局配置
  • 逐步移除分散的注解配置
  • 最终统一到1-2种管理方式

Spring Cloud微服务:

  • 在API Gateway统一处理CORS
  • 各微服务禁用CORS或仅允许网关源
  • 结合OAuth2等安全机制

6.3 终极建议

生产环境不要使用*作为允许源 - 明确列出可信域名

限制允许的方法和头 - 按最小权限原则配置

合理设置maxAge - 平衡安全性和性能(建议1小时)

与前端团队协作 - 确保双方对CORS要求理解一致

监控CORS错误 - 及时发现配置问题或恶意请求

通过合理配置CORS,可以在保障安全性的同时,为现代前后端分离架构提供必要的跨域支持。Spring Boot提供了多种灵活的方式,开发者应根据项目实际需求选择最适合的方案。

到此这篇关于SpringBoot中处理跨域请求CORS的全面指南的文章就介绍到这了,更多相关SpringBoot跨域请求CORS内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java数组的动态初始化和常见问题解析

    Java数组的动态初始化和常见问题解析

    本文介绍了数组动态初始化的概念,即在初始化时仅指定数组长度,系统会为数组分配初始值,而静态初始化则手动指定数组元素,系统根据元素个数计算数组长度,这两种初始化方式应用场景不同,另外,还讲述了数组默认初始化值的规律及数组常见问题,如越界问题等
    2024-10-10
  • JetCache 缓存框架的使用及源码解析(推荐)

    JetCache 缓存框架的使用及源码解析(推荐)

    JetCache是一个基于Java的缓存系统封装,提供统一的API和注解来简化缓存的使用。本文重点给大家介绍JetCache 缓存框架的使用及源码分析,感兴趣的朋友一起看看吧
    2022-01-01
  • SpringBoot学习篇之@Valid与@Validated的区别

    SpringBoot学习篇之@Valid与@Validated的区别

    @Valid是使用Hibernate validation的时候使用,@Validated是只用Spring Validator校验机制使用,下面这篇文章主要给大家介绍了关于SpringBoot学习篇之@Valid与@Validated区别的相关资料,需要的朋友可以参考下
    2022-11-11
  • 深入理解Java设计模式之代理模式

    深入理解Java设计模式之代理模式

    这篇文章主要介绍了Java设计模式之代理模式的的相关资料,文中示例代码非常详细,供大家参考和学习,感兴趣的朋友可以了解下
    2021-11-11
  • java音乐播放器课程设计

    java音乐播放器课程设计

    这篇文章主要为大家详细介绍了java音乐播放器的课程设计,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-06-06
  • Java获取路径的6种方式代码示例

    Java获取路径的6种方式代码示例

    在Java中获取路径的方法有多种,每种方法适用于不同的场景,这篇文章主要介绍了Java获取路径的6种方式,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2025-02-02
  • Java内存各部分OOM出现原因及解决方法(必看)

    Java内存各部分OOM出现原因及解决方法(必看)

    下面小编就为大家带来一篇Java内存各部分OOM出现原因及解决方法(必看)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-04-04
  • 解决bean对象注入报错:Field in required a bean of type‘‘that could not be found.问题

    解决bean对象注入报错:Field in required a bean&nb

    这篇文章主要介绍了解决bean对象注入报错:Field in required a bean of type‘‘that could not be found.问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2025-06-06
  • Java树形结构数据生成导出excel文件方法记录

    Java树形结构数据生成导出excel文件方法记录

    最近好像得罪了poi,遇到的都是导出word、Excel、pdf的问题,下面这篇文章主要给大家介绍了关于Java树形结构数据生成导出excel文件的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考下
    2021-10-10
  • 区分Java的方法覆盖与变量覆盖

    区分Java的方法覆盖与变量覆盖

    作为初学者2个比较容易出错的定义,方法覆盖和变量覆盖。下面我们一起来看看作者如何去探讨Java的方法覆盖和变量覆盖。
    2015-09-09

最新评论