Java案例:如何配置跨域规则?从入门到生产级配置详解
目录导读
- 跨域基础:为什么会出现跨域问题?
- Java跨域配置的三种核心方式
- Spring Boot案例:CORS全局配置
- Spring Security整合:安全与跨域共存
- 手写Filter:最灵活的跨域控制
- 常见问题与解决(Q&A)
- 生产环境最佳实践
跨域基础:为什么会出现跨域问题?
Q:什么是跨域? A:跨域指浏览器从一个域名的网页去请求另一个域名的资源时,由于浏览器的同源策略限制(协议、域名、端口任一不同),请求会被阻止。

Q:跨域只影响前端吗? A:是的,跨域是浏览器的安全行为,服务端本身并不阻止请求,但浏览器会拦截响应,需要在服务端配置规则,告知浏览器允许哪些域访问。
关键概念
- Origin(源):
http://localhost:8080就是一个完整的源。 - 预检请求(Preflight):对于非简单请求(如自定义Header、PUT/DELETE方法),浏览器会先发一个
OPTIONS请求确认服务器是否允许。
Java跨域配置的三种核心方式
Java环境(Spring Boot、Servlet、Spring Security)下的跨域配置,本质上是在HTTP响应头中加入CORS相关的字段,核心Header包括:
| Header字段 | 作用 |
|---|---|
Access-Control-Allow-Origin |
允许的源(如 或 http://example.com) |
Access-Control-Allow-Methods |
允许的HTTP方法 |
Access-Control-Allow-Headers |
允许的请求头 |
Access-Control-Max-Age |
预检请求的缓存时间 |
*Q:为什么不能直接在所有场景用 `?** A:*无法配合withCredentials`(携带Cookie)使用;且生产环境建议指定具体域名,防止任意站点访问。
Spring Boot案例:CORS全局配置
WebMvcConfigurer 配置(推荐)
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**") // 匹配所有/api路径
.allowedOrigins("http://localhost:3000") // 允许的前端域名
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
.allowedHeaders("*")
.allowCredentials(true) // 允许携带Cookie
.maxAge(3600); // 缓存预检请求1小时
}
}
*Q:allowCredentials(true) 和 `allowedOrigins("")为什么不能同时使用?** A:浏览器安全策略要求,当允许携带凭证时,必须明确指定可信任的源,不能使用通配符,此时可改为allowedOrigins("http://localhost:3000")`。
@CrossOrigin 注解(局部配置)
@RestController
@CrossOrigin(origins = "http://localhost:3000", maxAge = 3600)
public class UserController {
@GetMapping("/user/info")
public UserInfo getInfo() { /* ... */ }
}
适用场景:仅对少数接口开放跨域。
Spring Security整合:安全与跨域共存
当项目中同时使用 Spring Security 时,跨域配置必须在 Security 过滤器链之前生效,否则,未通过认证的请求会被拦截,连OPTIONS预检请求都无法通过。
配置示例
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.cors(cors -> cors.configurationSource(corsConfigurationSource())) // 启用CORS
.csrf(csrf -> csrf.disable()) // 注意:跨域时通常关闭CSRF
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/public/**").permitAll()
.anyRequest().authenticated()
);
return http.build();
}
@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration config = new CorsConfiguration();
config.setAllowedOrigins(Arrays.asList("http://localhost:3000"));
config.setAllowedMethods(Arrays.asList("GET","POST","PUT","DELETE","OPTIONS"));
config.setAllowedHeaders(Arrays.asList("*"));
config.setAllowCredentials(true);
config.setMaxAge(3600L);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return source;
}
}
Q:为什么跨域时需要关闭CSRF? A:跨域请求本身可能携带Cookie,而CSRF防护会检查Token,实际项目中,如果前端与后端不在同一域名,可采用Token认证(如JWT)替代Cookie认证。
手写Filter:最灵活的跨域控制
对于非Spring Boot项目或需自定义逻辑的场景,可使用Filter拦截所有请求,动态添加Header。
@WebFilter("/*")
public class SimpleCorsFilter 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", "http://localhost:3000");
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");
// 预检请求直接返回200
if ("OPTIONS".equalsIgnoreCase(((HttpServletRequest) req).getMethod())) {
response.setStatus(HttpServletResponse.SC_OK);
} else {
chain.doFilter(req, res);
}
}
}
Q:为什么要单独处理OPTIONS请求? A:预检请求不需要真正的业务处理,直接返回成功状态即可,这样可以减轻后续过滤器(如认证过滤器)的负担。
常见问题与解决(Q&A)
Q:配置后前端依然报跨域错误?
- 检查是否配置了
Access-Control-Allow-Credentials但未指定具体域名。 - 确认请求头中
Origin值是否在allowedOrigins列表里。 - 检查是否有Nginx等代理层也拦截了跨域响应头。
Q:生产环境如何动态配置允许的域名?
使用配置项:@Value("${cors.allowed.origins}") 从application.yml读取域名列表,而非硬编码。
Q:局部@CrossOrigin与全局WebMvcConfigurer冲突吗? 注解优先级更高,若全局配置允许所有源,但某个接口用注解限制了源,则注解生效。
生产环境最佳实践
- *杜绝使用 `
**:生产环境务必指定具体的源列表,如http://www.example.com`。 - 单独管理跨域配置中心:可用数据库或配置中心动态更新允许的源,避免重启服务。
- 预检请求缓存优化:设置合理的
maxAge(如86400秒即24小时),减少频繁的OPTIONS请求。 - 结合API网关:在网关层统一配置跨域,后端应用无需再关心跨域逻辑。
- 安全建议:跨域与CSRF、XSS防护结合使用,对携带Cookie的请求,确保Https传输。
跨域配置的核心在于服务端正确返回CORS响应头,根据项目架构选择配置方式——简单单体用WebMvcConfigurer,有Security用SecurityFilterChain,非Spring项目用Filter,生产环境记住两条铁律:明确源 + 关闭通配符。
本文基于Spring Boot 2.7+和Spring Security 6.x编写,适用主流Java Web应用场景。