springboot如何解决跨域问题?

在Spring Boot中解决跨域问题有几种常用方法,以下是详细的解决方案:

1. 使用@CrossOrigin注解(局部配置)

在控制器类或方法上添加注解

// 在控制器类上使用
@RestController
@CrossOrigin(origins = "http://localhost:3000")
@RequestMapping("/api")
public class MyController {
    
    // 或者在具体方法上使用
    @GetMapping("/users")
    @CrossOrigin(origins = "http://localhost:3000")
    public List<User> getUsers() {
        return userService.findAll();
    }
}

配置多个参数

@CrossOrigin(
    origins = {"http://localhost:3000", "https://example.com"},
    methods = {RequestMethod.GET, RequestMethod.POST},
    allowedHeaders = "*",
    allowCredentials = "true",
    maxAge = 3600
)

2. 全局配置(推荐)

方法一:实现WebMvcConfigurer接口

@Configuration
public class CorsConfig implements WebMvcConfigurer {
    
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/api/**")  // 配置路径
            .allowedOriginPatterns("*")  // Spring Boot 2.4.0+ 使用 allowedOriginPatterns
            // .allowedOrigins("http://localhost:3000")  // 2.4.0之前版本
            .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
            .allowedHeaders("*")
            .allowCredentials(true)
            .maxAge(3600);
            
        // 可以配置多个路径规则
        registry.addMapping("/public/**")
            .allowedOriginPatterns("*")
            .allowedMethods("GET");
    }
}

方法二:使用CorsFilter过滤器

@Configuration
public class CorsConfig {
    
    @Bean
    public CorsFilter corsFilter() {
        CorsConfiguration config = new CorsConfiguration();
        
        // 允许的源
        config.addAllowedOriginPattern("*");
        // 允许的请求头
        config.addAllowedHeader("*");
        // 允许的请求方法
        config.addAllowedMethod("*");
        // 是否允许发送Cookie
        config.setAllowCredentials(true);
        // 预检请求的有效期
        config.setMaxAge(3600L);
        
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", config);
        
        return new CorsFilter(source);
    }
}

3. 在Spring Security中配置跨域

如果项目使用了Spring Security,需要在Security配置中启用CORS:

@Configuration
@EnableWebSecurity
public class SecurityConfig {
    
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .cors()  // 启用CORS配置
                .and()
            .csrf().disable()  // 如果前端有CSRF处理可以不禁用
            .authorizeHttpRequests(authz -> authz
                .requestMatchers("/api/public/**").permitAll()
                .anyRequest().authenticated()
            );
        
        return http.build();
    }
    
    // 提供CORS配置源
    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOriginPatterns(Arrays.asList("*"));
        configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS"));
        configuration.setAllowedHeaders(Arrays.asList("*"));
        configuration.setAllowCredentials(true);
        configuration.setMaxAge(3600L);
        
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }
}

4. 通过application.yml/properties配置

# application.yml
spring:
  web:
    cors:
      allowed-origins: "http://localhost:3000,https://example.com"
      allowed-methods: "GET,POST,PUT,DELETE,OPTIONS"
      allowed-headers: "*"
      allow-credentials: true
      max-age: 3600

5. 处理OPTIONS预检请求

对于复杂请求,浏览器会先发送OPTIONS预检请求:

@Configuration
public class WebConfig implements WebMvcConfigurer {
    
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
            .allowedOriginPatterns("*")
            .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")  // 必须包含OPTIONS
            .allowedHeaders("*")
            .exposedHeaders("Authorization", "X-Custom-Header")  // 暴露自定义响应头
            .allowCredentials(true)
            .maxAge(3600);
    }
}

6. 解决常见问题

问题1:CORS与Cookie/Session

// 前后端分离项目,如果需要携带Cookie
@CrossOrigin(origins = "http://localhost:3000", allowCredentials = "true")

// 前端请求需要设置
// fetch(url, { credentials: 'include' })

问题2:多域配置

@CrossOrigin(origins = {"http://localhost:3000", "https://admin.example.com"})

// 或者使用通配符
.allowedOriginPatterns("http://*.example.com", "https://*.example.com")

问题3:自定义响应头

@Override
public void addCorsMappings(CorsRegistry registry) {
    registry.addMapping("/**")
        .exposedHeaders("X-Total-Count", "X-Custom-Token");  // 暴露自定义响应头
}

推荐方案

  1. 开发环境:使用全局配置的allowedOriginPatterns("*")方便开发
  2. 生产环境:明确指定允许的域名,如.allowedOriginPatterns("https://yourdomain.com")
  3. 前后端分离项目:结合Spring Security配置,确保安全性
  4. 微服务架构:在API Gateway层统一处理跨域

注意事项

  1. Spring Boot 2.4.0+ 使用allowedOriginPatterns替代allowedOrigins
  2. 设置allowCredentials(true)时,不能使用allowedOrigins("*")
  3. 复杂请求(如带自定义头、非简单方法)会触发OPTIONS预检请求
  4. 注意响应头的大小写,浏览器对某些头是大小写敏感的

作 者:南烛
链 接:https://www.itnotes.top/archives/1036
来 源:IT笔记
文章版权归作者所有,转载请注明出处!


上一篇
下一篇