[Java实战]Spring Boot 解决跨域问题(十四)
一、CORS 问题背景
-
什么是跨域问题?
当浏览器通过 JavaScript 发起跨域请求(不同协议、域名、端口)时,会触发同源策略限制,导致请求被拦截。
示例场景:前端运行在http://localhost:3000
,后端 API 部署在http://localhost:8080
。 -
CORS 机制的作用
- CORS(Cross-Origin Resource Sharing)是一种基于 HTTP 头的安全机制。
- 允许服务端声明哪些外部域可以访问资源,解决合法跨域请求的限制。
二、Spring Boot 的 4 种解决方案
1. 使用 @CrossOrigin
注解(Controller 级别)
适用场景:仅需为单个接口或控制器开启跨域支持。
实现方式:
@RestController
@RequestMapping("/api")
public class UserController {@CrossOrigin(origins = "http://localhost:3000")@GetMapping("/users")public List<User> getUsers() {return userService.findAll();}
}
配置参数:
origins
:允许的源(支持通配符*
,但不推荐生产环境使用)methods
:允许的 HTTP 方法(如GET, POST
)allowedHeaders
:允许的请求头(如Content-Type, Authorization
)maxAge
:预检请求缓存时间(单位:秒)
2. 全局 CORS 配置(推荐)
适用场景:为整个应用统一配置跨域规则。
实现方式:
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {@Overridepublic void addCorsMappings(CorsRegistry registry) {registry.addMapping("/**").allowedOrigins("http://localhost:3000").allowedMethods("GET", "POST", "PUT", "DELETE").allowedHeaders("*").allowCredentials(true).maxAge(3600);}
}
关键配置说明:
addMapping("/**")
:对所有接口生效allowCredentials(true)
:允许携带 Cookie(需与allowedOrigins
明确指定域名配合)
3. 结合 Spring Security 的 CORS 配置
适用场景:应用启用了 Spring Security 鉴权,需确保 CORS 配置不被安全过滤器拦截。
实现方式:
@Configuration
@EnableWebSecurity
public class SecurityConfig {@Beanpublic SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {http.cors(cors -> cors.configurationSource(corsConfigurationSource())).csrf().disable().authorizeRequests(auth -> auth.anyRequest().authenticated());return http.build();}@BeanCorsConfigurationSource corsConfigurationSource() {CorsConfiguration config = new CorsConfiguration();config.setAllowedOrigins(Arrays.asList("http://localhost:3000"));config.setAllowedMethods(Arrays.asList("GET", "POST"));UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();source.registerCorsConfiguration("/**", config);return source;}
}
注意事项:
- 必须通过
cors.configurationSource()
显式配置,而非仅依赖WebMvcConfigurer
。 - 确保 Spring Security 的过滤器链顺序正确(CORS 处理需在认证之前)。
4. 网关层统一处理(Nginx/Spring Cloud Gateway)
适用场景:微服务架构中,在网关层统一管理跨域策略。
示例(Nginx 配置):
server {listen 80;server_name api.example.com;location / {# CORS 配置add_header 'Access-Control-Allow-Origin' 'http://localhost:3000';add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,Content-Type,Authorization';add_header 'Access-Control-Allow-Credentials' 'true';if ($request_method = 'OPTIONS') {add_header 'Access-Control-Max-Age' 1728000;add_header 'Content-Type' 'text/plain; charset=utf-8';add_header 'Content-Length' 0;return 204;}proxy_pass http://backend-service;}
}
三、最佳实践与调试技巧
-
避免使用通配符
*
- 生产环境中明确指定
allowedOrigins
,如https://your-frontend-domain.com
。 - 通配符会导致
allowCredentials(true)
失效,且存在安全风险。
- 生产环境中明确指定
-
处理预检请求(OPTIONS)
- 浏览器对复杂请求(如带自定义头的 POST)会先发送 OPTIONS 请求。
- 确保后端正确处理 OPTIONS 方法(可通过全局配置或网关层实现)。
-
调试工具推荐
- 浏览器开发者工具:查看 Console 和 Network 标签中的 CORS 错误信息。
- Postman:验证接口是否正常工作(绕过浏览器限制)。
- curl 命令:模拟跨域请求:
curl -H "Origin: http://localhost:3000" -H "Access-Control-Request-Method: GET" -X OPTIONS http://localhost:8080/api/users
四、常见问题排查
-
配置未生效的可能原因
- 未正确引入
WebMvcConfigurer
或 Spring Security 配置冲突。 - 全局配置与
@CrossOrigin
注解混用时优先级问题(注解会覆盖全局配置)。 - 缓存问题:浏览器可能缓存了旧的 CORS 响应头,需强制刷新(
Ctrl + F5
)。
- 未正确引入
-
Spring Security 导致 CORS 失效
- 检查安全配置中是否遗漏
.cors()
调用。 - 确保
CorsConfigurationSource
Bean 被正确注册。
- 检查安全配置中是否遗漏
-
携带 Cookie 时的特殊要求
- 前端请求需设置
withCredentials: true
(Axios 示例):axios.get('http://localhost:8080/api/data', { withCredentials: true });
- 后端需配置
allowCredentials(true)
且allowedOrigins
不能为*
。
- 前端请求需设置
五、进阶:CORS 与 CSRF 的协同配置
若同时启用 CSRF 保护(如表单提交场景):
@Configuration
@EnableWebSecurity
public class SecurityConfig {@Beanpublic SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {http.cors().configurationSource(corsConfigurationSource()).and().csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()).and().authorizeRequests().anyRequest().authenticated();return http.build();}
}
关键点:
- 使用
CookieCsrfTokenRepository
将 CSRF Token 存储在 Cookie 中。 - 前端需从 Cookie 读取
XSRF-TOKEN
并添加到请求头。
六、总结
通过合理选择注解配置、全局策略或网关层处理,Spring Boot 可以灵活解决各种跨域场景。关键点在于:
- 明确需求:区分开发环境与生产环境的配置严格性。
- 安全优先:避免过度开放权限,严格限制
allowedOrigins
。 - 全链路验证:结合浏览器工具和后端日志进行调试。
附录:官方文档参考
- Spring CORS Documentation
- MDN CORS Guide
希望本教程对您有帮助,请点赞❤️收藏⭐关注支持!欢迎在评论区留言交流技术细节!