在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"); // 暴露自定义响应头
}
推荐方案
- 开发环境:使用全局配置的
allowedOriginPatterns("*")方便开发 - 生产环境:明确指定允许的域名,如
.allowedOriginPatterns("https://yourdomain.com") - 前后端分离项目:结合Spring Security配置,确保安全性
- 微服务架构:在API Gateway层统一处理跨域
注意事项
- Spring Boot 2.4.0+ 使用
allowedOriginPatterns替代allowedOrigins - 设置
allowCredentials(true)时,不能使用allowedOrigins("*") - 复杂请求(如带自定义头、非简单方法)会触发OPTIONS预检请求
- 注意响应头的大小写,浏览器对某些头是大小写敏感的