什么是跨域问题
跨域问题(Cross-Origin Resource Sharing, CORS)是浏览器基于同源策略(Same-Origin Policy)实施的一种安全机制,它限制了从不同源(协议、域名、端口任一不同)加载的资源如何交互。在现代Web开发中,前后端分离架构非常普遍,跨域问题成为开发者必须面对的挑战。
Spring Boot中的跨域解决方案
Spring Boot提供了多种方式来解决跨域问题,下面我将详细介绍几种常用的全局跨域配置方案。
1. 使用@CrossOrigin注解
最简单的方式是在Controller类或方法上添加@CrossOrigin
注解:
@RestController
@RequestMapping("/api")
@CrossOrigin(origins = "*")
public class MyController {
// 类级别的跨域配置会应用到所有方法
@GetMapping("/hello")
@CrossOrigin(origins = "http://localhost:8080") // 方法级别可以覆盖类级别配置
public String hello() {
return "Hello, World!";
}
}
优点:简单直接,适合细粒度控制
缺点:需要在每个Controller或方法上添加注解,不适合全局配置
2. 实现WebMvcConfigurer接口
更推荐的方式是实现WebMvcConfigurer
接口并重写addCorsMappings
方法:
@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); // 预检请求缓存时间
}
}
优点:
- 全局配置,一次编写,多处生效
- 配置灵活,可以针对不同路径设置不同规则
- 支持各种CORS相关参数设置
缺点:
- 需要理解CORS相关概念才能正确配置
3. 使用CorsFilter过滤器
对于更复杂的需求,可以创建自定义的CORS过滤器:
@Configuration
public class GlobalCorsConfig {
@Bean
public CorsFilter corsFilter() {
// 1. 创建CORS配置对象
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true); // 允许cookies跨域
config.addAllowedOriginPattern("*"); // 允许所有域
config.addAllowedHeader("*"); // 允许所有头
config.addAllowedMethod("*"); // 允许所有方法
// 2. 为URL添加映射路径
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
// 3. 返回新的CorsFilter
return new CorsFilter(source);
}
}
适用场景:
- 需要与Spring Security集成时
- 需要更细粒度的控制时
- 项目中使用过滤器链时
4. Spring Security中的CORS配置
如果项目使用了Spring Security,需要在Security配置中显式启用CORS支持:
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors() // 启用CORS
.and()
// 其他安全配置...
.csrf().disable();
}
@Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("*"));
configuration.setAllowedMethods(Arrays.asList("*"));
configuration.setAllowedHeaders(Arrays.asList("*"));
configuration.setAllowCredentials(true);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}
注意事项:
- 使用Spring Security时,必须显式配置CORS
- 需要同时配置
cors()
和提供CorsConfigurationSource
bean
配置参数详解
在配置CORS时,有几个关键参数需要理解:
- allowedOrigins:允许访问的源列表,
*
表示允许所有源 - allowedMethods:允许的HTTP方法(GET, POST等)
- allowedHeaders:允许的请求头
- allowCredentials:是否允许发送cookie等凭证
- maxAge:预检请求的缓存时间(秒)
- exposedHeaders:允许暴露给客户端的响应头
常见问题与解决方案
1. 预检请求(Preflight Request)问题
对于非简单请求(如Content-Type为application/json的POST请求),浏览器会先发送OPTIONS请求进行预检。
解决方案:
- 确保服务器正确处理OPTIONS方法
- 配置中包含OPTIONS方法:
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
2. 带凭证的请求问题
当请求需要携带cookie或认证信息时:
解决方案:
- 设置
allowCredentials(true)
- 不能使用
allowedOrigins("*")
,必须指定具体域名 - 使用
allowedOriginPatterns
代替allowedOrigins
(Spring Boot 2.4.0+)
3. 响应头被过滤问题
某些自定义响应头可能被浏览器拦截。
解决方案:
- 配置
exposedHeaders
暴露需要的头信息
最佳实践建议
- 生产环境不要使用
*
:在生产环境中,应该明确指定允许的源,而不是使用通配符 - 合理设置缓存时间:对于频繁的跨域请求,适当增加maxAge可以减少预检请求
- 与Spring Security集成注意顺序:确保CORS配置在Spring Security的认证过滤器之前
- 考虑使用网关统一处理:在微服务架构中,可以考虑在API网关层统一处理CORS,而不是在每个服务中配置
总结
Spring Boot提供了多种灵活的方式来处理跨域问题,开发者可以根据项目需求选择最适合的方案。对于大多数应用,实现WebMvcConfigurer
接口的方式提供了良好的平衡点,既保持了配置的简洁性,又能满足全局跨域需求。在更复杂的场景下,特别是与Spring Security集成时,使用CorsFilter
或显式配置CorsConfigurationSource
可能是更好的选择。
正确配置CORS不仅能解决开发中的跨域问题,还能为应用提供适当的安全保障,是开发现代Web应用不可或缺的一部分。