本文目录导读:

- 核心概念:什么是跨域?
- 方案一:Spring Boot 微服务后端
- 方案二:Spring Cloud Gateway 网关层
- 方案三:Java Web 原生过滤器(非 Spring 框架)
- 常见问题排查
- 最终建议
Java 中解决跨域问题的配置方案,主要取决于你的应用架构,下面整理了三种最常见的场景(Spring Boot、Spring Cloud Gateway、以及原始的 Servlet Filter),你可以直接参考。
核心概念:什么是跨域?
浏览器出于安全考虑,有同源策略,当请求的协议、域名、端口三者中任意一个与当前页面不同,就会产生跨域。
解决跨域的常用思路是服务器在响应头中返回 Access-Control-Allow-Origin 等字段,告诉浏览器“这个请求我允许”,这被称为 CORS(跨域资源共享)。
方案一:Spring Boot 微服务后端
如果你的后端是 Spring Boot,这是最常用、最推荐的方式。
方式 A:全局配置(推荐,适合整个项目的所有接口)
添加一个配置类,实现 WebMvcConfigurer,并重写 addCorsMappings 方法。
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**") // 允许所有路径
.allowedOriginPatterns("*") // 允许所有来源(用 patterns 更安全,支持通配符)
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") // 允许的方法
.allowedHeaders("*") // 允许所有请求头
.allowCredentials(true) // 允许携带 cookie
.maxAge(3600); // 预检请求的有效期,单位秒,1小时内不用再发预检
}
}
注意:allowedOriginPatterns("*") 比 allowedOrigins("*") 更灵活,尤其是在开启了 allowCredentials(true) 时。
方式 B:注解方式(适合某个特定 Controller 或方法)
在 Controller 类或方法上使用 @CrossOrigin 注解。
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api")
@CrossOrigin(origins = "http://localhost:3000") // 允许指定域名
public class UserController {
@GetMapping("/user")
public String getUser() {
return "Hello, CORS!";
}
}
方案二:Spring Cloud Gateway 网关层
如果你使用了微服务网关,可以在网关层面统一处理,避免在每个微服务里重复配置。
在 application.yml 或 bootstrap.yml 中配置跨域过滤器:
spring:
cloud:
gateway:
globalcors:
cors-configurations:
'[/**]':
allowedOriginPatterns: "*" # 允许的来源
allowedMethods: "*" # 允许的方法
allowedHeaders: "*" # 允许的请求头
allowCredentials: true # 允许携带凭证
maxAge: 3600
方案三:Java Web 原生过滤器(非 Spring 框架)
如果你的项目是原始的 Servlet 应用,没有使用 Spring 框架,可以写一个过滤器:
import javax.servlet.*;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class CorsFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin", "*"); // 允许所有来源(生产环境建议指定具体域名)
response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
response.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
response.setHeader("Access-Control-Max-Age", "3600");
// 处理预检请求:如果是 OPTIONS 请求,直接返回 200
String method = ((javax.servlet.http.HttpServletRequest) req).getMethod();
if ("OPTIONS".equalsIgnoreCase(method)) {
response.setStatus(HttpServletResponse.SC_OK);
return;
}
chain.doFilter(req, res);
}
@Override
public void init(FilterConfig filterConfig) {}
@Override
public void destroy() {}
}
然后在 web.xml 中注册这个过滤器。
常见问题排查
问题 1:前端报错 The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'
- 原因:你设置了
allowCredentials(true)和allowedOrigins("*"),这两者不能同时使用(这是浏览器安全限制)。 - 解决:将
allowedOrigins("*")改为allowedOriginPatterns("*")(Spring Boot 2.4+ 支持),或者指定具体的域名。
问题 2:预检请求(OPTIONS)返回 403
- 原因:Spring Security 拦截了 OPTIONS 请求。
- 解决:在 Spring Security 配置中放行 OPTIONS 请求和 OPTIONS 方法。
// 在 SecurityConfig 中
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.cors() // 开启 CORS 支持
.and()
.csrf().disable()
.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS, "/**").permitAll() // 放行 OPTIONS 请求
.anyRequest().authenticated();
}
问题 3:使用了 Nginx 或反向代理
如果你的请求经过了 Nginx,还需要确认 Nginx 是否正确转发了 OPTIONS 请求,或者是否在 Nginx 层面配置了 CORS(有时 Nginx 的配置会覆盖后端的 CORS 设置)。
最终建议
- 开发环境:直接使用
allowedOriginPatterns("*")或@CrossOrigin快速调试。 - 生产环境:
allowedOriginPatterns限定为前端部署的具体域名(如https://www.yourdomain.com),不要使用通配符。 - 网关与微服务:只在网关层配置 CORS,微服务内部不再单独配置,这样职责更清晰。