SpringBoot处理跨域请求(CORS)的五种方式

 更新时间:2025年04月20日 08:26:41   作者:北辰alk  
跨域资源共享(CORS)是现代Web开发中常见的问题,Spring Boot提供了多种方式来处理CORS请求,下面我将详细介绍各种实现方式及其适用场景,需要的朋友可以参考下

一、CORS基础概念

1. 什么是跨域请求?

当浏览器从一个域名的网页去请求另一个域名的资源时,如果域名、端口或协议不同,就会产生跨域请求。出于安全考虑,浏览器默认会阻止这类请求。

2. 简单请求 vs 预检请求

类型条件处理方式
简单请求GET/HEAD/POST方法,且Content-Type为text/plain、multipart/form-data或application/x-www-form-urlencoded直接发送请求,带Origin头
预检请求(OPTIONS)不符合简单请求条件的其他请求先发送OPTIONS请求,获得许可后再发送实际请求

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

1. 使用@CrossOrigin注解

适用场景:针对单个控制器或方法级别的CORS配置

@RestController
@RequestMapping("/api")
public class MyController {
    
    // 允许特定源的跨域访问
    @CrossOrigin(origins = "https://example.com")
    @GetMapping("/resource")
    public ResponseEntity<String> getResource() {
        return ResponseEntity.ok("跨域资源");
    }
    
    // 更详细的配置
    @CrossOrigin(origins = {"https://example.com", "https://api.example.com"},
                allowedHeaders = {"Content-Type", "Authorization"},
                methods = {RequestMethod.GET, RequestMethod.POST},
                maxAge = 3600)
    @PostMapping("/save")
    public ResponseEntity<String> saveResource() {
        return ResponseEntity.ok("保存成功");
    }
}

2. 全局CORS配置

适用场景:应用级别的统一CORS配置

@Configuration
public class WebConfig implements WebMvcConfigurer {
    
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/api/**")  // 匹配的路径
                .allowedOrigins("https://example.com", "https://api.example.com") // 允许的源
                .allowedMethods("GET", "POST", "PUT", "DELETE") // 允许的方法
                .allowedHeaders("*") // 允许的请求头
                .exposedHeaders("Authorization", "Content-Disposition") // 暴露的响应头
                .allowCredentials(true) // 是否允许发送cookie
                .maxAge(3600); // 预检请求缓存时间(秒)
        
        // 可以添加多个配置
        registry.addMapping("/public/**")
                .allowedOrigins("*");
    }
}

3. 使用Filter处理CORS

适用场景:需要更底层控制或与非Spring Web环境集成

@Configuration
public class CorsFilterConfig {
    
    @Bean
    public FilterRegistrationBean<CorsFilter> corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration config = new CorsConfiguration();
        
        // 配置CORS规则
        config.setAllowCredentials(true);
        config.addAllowedOrigin("https://example.com");
        config.addAllowedHeader("*");
        config.addAllowedMethod("*");
        config.setMaxAge(3600L);
        
        // 对所有路径生效
        source.registerCorsConfiguration("/**", config);
        
        FilterRegistrationBean<CorsFilter> bean = 
            new FilterRegistrationBean<>(new CorsFilter(source));
        bean.setOrder(Ordered.HIGHEST_PRECEDENCE); // 设置最高优先级
        
        return bean;
    }
}

4. Spring Security中的CORS配置

适用场景:使用Spring Security的项目

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.cors().and() // 启用CORS支持
            .csrf().disable() // 通常CORS和CSRF不能同时使用
            .authorizeRequests()
            .antMatchers("/api/public/**").permitAll()
            .anyRequest().authenticated();
    }
    
    // 提供CORS配置源
    @Bean
    CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(Arrays.asList("https://example.com"));
        configuration.setAllowedMethods(Arrays.asList("GET", "POST"));
        configuration.setAllowedHeaders(Arrays.asList("*"));
        
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        
        return source;
    }
}

5. 响应头手动设置

适用场景:需要动态控制CORS头

@RestController
public class DynamicCorsController {
    
    @GetMapping("/dynamic-cors")
    public ResponseEntity<String> dynamicCors(HttpServletRequest request, 
                                           HttpServletResponse response) {
        // 根据请求动态设置CORS头
        String origin = request.getHeader("Origin");
        if (isAllowedOrigin(origin)) {
            response.setHeader("Access-Control-Allow-Origin", origin);
            response.setHeader("Access-Control-Allow-Credentials", "true");
            response.setHeader("Access-Control-Allow-Methods", "GET, POST");
        }
        
        return ResponseEntity.ok("动态CORS响应");
    }
    
    private boolean isAllowedOrigin(String origin) {
        // 实现你的源验证逻辑
        return origin != null && origin.endsWith("example.com");
    }
}

三、CORS配置详解

1. 核心响应头说明

响应头说明
Access-Control-Allow-Origin允许访问的源,可以是具体域名或*(不推荐使用*,特别是需要凭证时)
Access-Control-Allow-Methods允许的HTTP方法(GET, POST等)
Access-Control-Allow-Headers允许的请求头
Access-Control-Expose-Headers浏览器可以访问的响应头
Access-Control-Allow-Credentials是否允许发送cookie(true/false),设为true时Allow-Origin不能为*
Access-Control-Max-Age预检请求结果的缓存时间(秒)

2. 常见问题解决方案

问题1:预检请求(OPTIONS)被拦截

解决方案

  • 确保OPTIONS请求不被安全框架拦截
  • 在Spring Security中配置:
http.cors().and()
    .authorizeRequests()
    .antMatchers(HttpMethod.OPTIONS, "/**").permitAll()

问题2:带凭证的请求失败

解决方案

  • 确保allowCredentials(true)和具体的allowedOrigins(不能是*)
  • 前端需要设置withCredentials: true(如axios)

问题3:特定响应头无法获取

解决方案

  • 使用exposedHeaders暴露需要的头:
.exposedHeaders("Custom-Header", "Authorization")

四、最佳实践建议

  • 生产环境不要使用通配符*:明确指定允许的源
  • 合理限制HTTP方法:只开放必要的方法(GET/POST等)
  • 考虑使用环境变量:动态配置允许的源
@Value("${cors.allowed.origins}")
private String[] allowedOrigins;

// 在配置中使用
.allowedOrigins(allowedOrigins)
  • 结合安全框架:Spring Security项目使用专门的CORS配置
  • 测试不同场景:简单请求和预检请求都要测试

五、完整配置示例

@Configuration
@EnableWebMvc
public class CorsConfig implements WebMvcConfigurer {
    
    @Value("${app.cors.allowed-origins}")
    private String[] allowedOrigins;
    
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/api/**")
                .allowedOrigins(allowedOrigins)
                .allowedMethods("GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS")
                .allowedHeaders("*")
                .exposedHeaders("Authorization", "Content-Disposition")
                .allowCredentials(true)
                .maxAge(3600);
                
        registry.addMapping("/public/**")
                .allowedOrigins("*")
                .allowedMethods("GET", "OPTIONS");
    }
    
    // 可选:提供CORS过滤器作为备选
    @Bean
    public FilterRegistrationBean<CorsFilter> corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration config = new CorsConfiguration();
        config.applyPermitDefaultValues();
        config.setAllowCredentials(true);
        config.setAllowedOrigins(Arrays.asList(allowedOrigins));
        source.registerCorsConfiguration("/**", config);
        
        FilterRegistrationBean<CorsFilter> bean = new FilterRegistrationBean<>(new CorsFilter(source));
        bean.setOrder(Ordered.HIGHEST_PRECEDENCE);
        return bean;
    }
}

六、总结

Spring Boot提供了多种灵活的方式来处理CORS:

  1. 简单场景:使用@CrossOrigin注解
  2. 统一配置:实现WebMvcConfigureraddCorsMappings方法
  3. 底层控制:配置CorsFilter
  4. 安全项目:结合Spring Security的cors()配置
  5. 动态需求:手动设置响应头

根据项目需求选择合适的方式,并遵循安全最佳实践,可以有效地解决跨域问题,同时保证应用的安全性。

以上就是SpringBoot处理跨域请求(CORS)的五种方式的详细内容,更多关于SpringBoot处理跨域请求的资料请关注脚本之家其它相关文章!

相关文章

  • 一个Java中BigDecimal的问题记录

    一个Java中BigDecimal的问题记录

    这篇文章主要给大家介绍了关于Java中一个BigDecimal问题的相关资料,通过文中介绍的方法可以很方便的解决BigDecimal进行计算的时候不管怎么计算,最后得到的值都没有变化的问题,需要的朋友可以参考下
    2021-11-11
  • mybatis-plus 查询时排除字段方法的两种方法

    mybatis-plus 查询时排除字段方法的两种方法

    我们在开发应用时,在某些应用场景下查询有时需要排除某些字段,本文主要介绍了两种方法,具有一定的参考价值,感兴趣的可以了解一下
    2023-09-09
  • Java通过URL获取公众号文章生成HTML的方法

    Java通过URL获取公众号文章生成HTML的方法

    这篇文章主要介绍了Java通过URL获取公众号文章生成HTML的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-12-12
  • JDK1.8新特性Stream流式操作的具体使用

    JDK1.8新特性Stream流式操作的具体使用

    这篇文章主要介绍了JDK1.8新特性Stream流式操作的具体使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-09-09
  • SpringBoot使用@SpringBootTest注解开发单元测试教程

    SpringBoot使用@SpringBootTest注解开发单元测试教程

    这篇文章主要介绍了SpringBoot使用@SpringBootTest注解开发单元测试教程,本文通过详细的案例过程来说明如何使用该项技术,需要的朋友可以参考下
    2021-06-06
  • springboot2.x整合tkmapper的示例代码

    springboot2.x整合tkmapper的示例代码

    这篇文章主要介绍了springboot2.x整合tkmapper,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-01-01
  • SpringBoot关闭过程中销毁DisposableBean解读

    SpringBoot关闭过程中销毁DisposableBean解读

    这篇文章主要介绍了SpringBoot关闭过程中销毁DisposableBean解读,一个bean的生命周期,指的是 bean 从创建,初始化,一系列使用,销毁的过程,今天来讲讲 bean 的初始化和销毁的方法,需要的朋友可以参考下
    2023-12-12
  • java 基础教程之多线程详解及简单实例

    java 基础教程之多线程详解及简单实例

    这篇文章主要介绍了java 基础教程之多线程详解及简单实例的相关资料,线程的基本属性、如何创建线程、线程的状态切换以及线程通信,需要的朋友可以参考下
    2017-03-03
  • Spring常用配置及解析类说明

    Spring常用配置及解析类说明

    这篇文章主要介绍了Spring常用配置及解析类说明,涉及Spring常用配置项的方法以及它的解析类等相关内容,具有一定参考价值,需要的朋友可以了解下。
    2017-11-11
  • Java设计模式之备忘录模式_动力节点Java学院

    Java设计模式之备忘录模式_动力节点Java学院

    我们在编程的时候,经常需要保存对象的中间状态,当需要的时候,可以恢复到这个状态。接下来通过本文给大家分享java设计模式之备忘录模式,感兴趣的的朋友一起看看吧
    2017-08-08

最新评论