Spring Boot跨域请求又被拦截了?这5种解决方案让你彻底告别CORS错误!
Spring Boot跨域请求又被拦截了?这5种解决方案让你彻底告别CORS错误!
本文来自公众号【服务端技术精选】,专注Java后端技术干货分享
大家好,我是你们的老朋友,一个在后端摸爬滚打了多年的老程序员。今天我们来聊聊一个让无数前端后端程序员都头疼的问题——跨域请求!
相信很多小伙伴在做前后端分离项目的时候,都被那个红彤彤的跨域错误折磨过。什么"CORS policy"、"blocked by CORS policy",看得人一脸懵逼。今天我就带大家彻底搞懂这个问题,让你从此告别跨域烦恼!
什么是跨域?为什么会有跨域限制?
首先我们要明白,跨域其实是一种安全机制,叫做"同源策略"。那什么叫"同源"呢?
简单来说,就是两个URL的协议、域名、端口都相同才算同源。比如:
http://www.example.com:8080和http://www.example.com:8080是同源的http://www.example.com:8080和https://www.example.com:8080就不是同源的(协议不同)http://www.example.com:8080和http://api.example.com:8080也不是同源的(域名不同)http://www.example.com:8080和http://www.example.com:9090也不是同源的(端口不同)
浏览器出于安全考虑,默认情况下不允许跨域请求。这就是为什么你在本地开发时,前端跑在3000端口,后端跑在8080端口,就会出现跨域问题。
Spring Boot中解决跨域的5种方法
方法一:使用@CrossOrigin注解(最简单)
这是最简单直接的方法,适合快速开发:
@RestController
@RequestMapping("/api")
@CrossOrigin(origins = "http://localhost:3000")
public class UserController {
@GetMapping("/users")
public List<User> getUsers() {
return userService.getAllUsers();
}
}
如果你想对整个Controller都开启跨域,可以直接加在类上;如果只想对某个方法开启,就加在方法上。
方法二:全局配置类(最灵活)
这种方法适合需要统一管理跨域配置的项目:
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("http://localhost:3000", "https://www.yourdomain.com")
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
.allowedHeaders("*")
.allowCredentials(true)
.maxAge(3600);
}
}
方法三:使用Filter过滤器(最底层)
如果你需要更底层的控制,可以使用Filter:
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class CorsFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
HttpServletRequest request = (HttpServletRequest) req;
response.setHeader("Access-Control-Allow-Origin", "http://localhost:3000");
response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "*");
response.setHeader("Access-Control-Allow-Credentials", "true");
if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
response.setStatus(HttpServletResponse.SC_OK);
} else {
chain.doFilter(req, res);
}
}
}
方法四:application.yml配置(最简洁)
在配置文件中也可以配置跨域:
spring:
web:
cors:
allowed-origins:
- "http://localhost:3000"
- "https://www.yourdomain.com"
allowed-methods:
- GET
- POST
- PUT
- DELETE
- OPTIONS
allowed-headers: "*"
allow-credentials: true
max-age: 3600
方法五:WebFlux配置(响应式编程)
如果你的项目使用了WebFlux,可以这样配置:
@Configuration
public class CorsConfig {
@Bean
public CorsWebFilter corsWebFilter() {
CorsConfiguration config = new CorsConfiguration();
config.addAllowedOrigin("http://localhost:3000");
config.addAllowedMethod("*");
config.addAllowedHeader("*");
config.setAllowCredentials(true);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return new CorsWebFilter(source);
}
}
实际应用案例和最佳实践
电商项目前后端分离架构
假设我们正在开发一个电商项目,前端用Vue,后端用Spring Boot:
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Value("${cors.allowed.origins}")
private String[] allowedOrigins;
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**")
.allowedOrigins(allowedOrigins)
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
.allowedHeaders("*")
.allowCredentials(true)
.maxAge(3600);
}
}
配置文件:
cors:
allowed:
origins:
- "http://localhost:8080"
- "https://shop.yourdomain.com"
- "https://admin.yourdomain.com"
微服务架构中的跨域处理
在微服务架构中,我们可以把跨域配置放在网关层:
@Configuration
public class GatewayCorsConfig {
@Bean
public CorsWebFilter corsWebFilter() {
CorsConfiguration config = new CorsConfiguration();
config.setAllowedOriginPatterns(Arrays.asList("*"));
config.addAllowedMethod("*");
config.addAllowedHeader("*");
config.setAllowCredentials(true);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return new CorsWebFilter(source);
}
}
多域名支持的复杂配置
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
// 开发环境
registry.addMapping("/api/dev/**")
.allowedOriginPatterns("http://localhost:*")
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
.allowCredentials(true);
// 生产环境
registry.addMapping("/api/prod/**")
.allowedOrigins("https://www.yourdomain.com", "https://admin.yourdomain.com")
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
.allowCredentials(true);
}
}
最佳实践建议
-
安全性考虑:永远不要在生产环境中使用
allowedOrigins("*"),这会带来安全风险。 -
性能优化:合理设置
maxAge参数,避免浏览器频繁发送预检请求。 -
日志记录:在生产环境中添加详细的日志记录,便于问题排查。
-
配置管理:通过配置文件管理不同环境的跨域配置。
常见问题排查和解决方案
配置不生效问题
首先检查配置类是否被正确加载:
@Component
public class CorsConfigChecker implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
System.out.println("CORS配置已加载!");
}
}
预检请求403错误
在拦截器中放行OPTIONS请求:
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 放行OPTIONS预检请求
if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
response.setStatus(HttpServletResponse.SC_OK);
return true;
}
return super.preHandle(request, response, handler);
}
Cookie无法传递问题
前端配置:
// 前端axios配置
axios.defaults.withCredentials = true;
后端配置:
.allowedOrigins("https://www.yourdomain.com") // 不能用*
.allowCredentials(true)
总结和进阶建议
今天我们详细讲解了Spring Boot中处理跨域请求的5种方法,每种方法都有自己的适用场景:
- @CrossOrigin注解 - 最简单,适合快速开发
- 全局配置类 - 最灵活,适合复杂的业务场景
- Filter过滤器 - 最底层,适合需要精细控制的场景
- application.yml配置 - 最简洁,适合配置驱动的项目
- WebFlux配置 - 最新潮,适合响应式编程项目
在实际项目中,我建议大家遵循以下原则:
安全第一:永远不要在生产环境中使用通配符配置,一定要明确指定允许访问的域名。
性能优化:合理设置maxAge参数,避免浏览器频繁发送预检请求。
配置统一:将CORS配置集中管理,通过配置文件来控制不同环境的配置。
日志完善:在生产环境中添加详细的日志记录,便于问题排查和监控。
跨域问题看似简单,但在实际项目中却经常给我们带来困扰。希望通过这篇文章,大家能够彻底掌握Spring Boot中处理CORS的各种方法,并能在实际工作中灵活运用。
记住一句话:技术的学习不是为了应付面试,而是为了解决实际问题。希望大家都能成为解决问题的高手!
如果觉得这篇文章对你有帮助,别忘了点赞、转发,让更多需要的兄弟看到。我们下期再见!
欢迎关注公众号【服务端技术精选】,每周分享实用的后端技术干货!
标题:Spring Boot跨域请求又被拦截了?这5种解决方案让你彻底告别CORS错误!
作者:jiangyi
地址:http://www.jiangyi.space/articles/2025/12/21/1766304282928.html