Spring MVC 中的 CORS 与 Controller 局部处理实践

在Web开发中,跨域问题是前后端分离架构下经常遇到的问题。最近在项目中深入研究了Spring MVC的CORS处理机制,总结了一些实用的经验和最佳实践。

跨域基础概念

同源策略

浏览器的同源策略是一个重要的安全机制,只有当协议、域名、端口三者完全相同时,才被认为是同源。任何一个不同都会触发跨域限制。

CORS机制

CORS(Cross-Origin Resource Sharing,跨域资源共享)是W3C标准,允许服务器声明哪些源站有权限访问资源。关键在于:跨域访问的控制权在服务端,而非前端

Spring MVC中的CORS处理策略

全局配置方式

通过实现WebMvcConfigurer接口,可以为整个应用设置统一的CORS策略:

1
2
3
4
5
6
7
8
9
10
11
12
13
@Configuration
public class MvcConfiguration implements WebMvcConfigurer {

@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**")
.allowedOrigins("http://localhost:3000", "https://yourdomain.com")
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
.allowedHeaders("*")
.allowCredentials(true)
.maxAge(3600);
}
}

全局配置的优势:

  • 一次配置,全局生效
  • 统一管理CORS策略
  • 自动处理预检请求(OPTIONS)

局部配置方式

使用@CrossOrigin注解可以在控制器级别或方法级别进行精细化控制:

1
2
3
4
5
6
7
8
9
10
11
@RestController
@CrossOrigin(origins = "http://localhost:3000")
public class ChatController {

@PostMapping("/chat")
@CrossOrigin(origins = "https://admin.yourdomain.com", methods = RequestMethod.POST)
public ResponseEntity<String> chat(@RequestBody ChatRequest request) {
// 业务逻辑
return ResponseEntity.ok("success");
}
}

配置优先级:
方法级@CrossOrigin > 类级@CrossOrigin > 全局addCorsMappings

跨域请求的完整流程

  1. 预检请求阶段:浏览器发送OPTIONS请求,询问服务器是否允许跨域
  2. 服务器响应:根据CORS配置返回相应的Access-Control-Allow-*头部
  3. 实际请求:预检通过后,浏览器发送真正的业务请求
  4. 业务处理:请求进入Controller方法执行具体业务逻辑
  5. 响应返回:服务器在响应中继续添加CORS头部,浏览器验证后放行

与Spring Security的集成

当项目使用Spring Security时,需要确保CORS处理在安全过滤器链之前执行:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Configuration
@EnableWebSecurity
public class SecurityConfig {

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.cors().and()
.authorizeHttpRequests(auth ->
auth.requestMatchers(HttpMethod.OPTIONS, "/**").permitAll()
.anyRequest().authenticated()
);
return http.build();
}
}

开发环境与生产环境的不同策略

开发环境

方案一:后端配置CORS

1
2
3
4
5
// 开发环境可以相对宽松
registry.addMapping("/**")
.allowedOrigins("http://localhost:3000", "http://127.0.0.1:3000")
.allowedMethods("*")
.allowCredentials(true);

方案二:前端代理

1
2
3
4
5
6
7
8
9
10
11
// vite.config.js
export default {
server: {
proxy: {
'/api': {
target: 'http://localhost:8080',
changeOrigin: true
}
}
}
}

生产环境

生产环境应该采用最小权限原则:

1
2
3
4
5
6
registry.addMapping("/api/**")
.allowedOrigins("https://yourdomain.com")
.allowedMethods("GET", "POST", "PUT", "DELETE")
.allowedHeaders("Content-Type", "Authorization")
.allowCredentials(true)
.maxAge(86400); // 24小时缓存

实际项目中的最佳实践

1. 分层配置策略

  • 全局配置:设置通用的CORS规则,作为默认策略
  • 局部配置:针对特殊接口进行精细化控制

2. 安全考虑

  • 生产环境避免使用通配符*
  • 明确指定允许的域名、方法和头部
  • 合理设置缓存时间maxAge

3. 调试技巧

  • 使用浏览器开发者工具查看预检请求
  • 检查响应头中的Access-Control-*字段
  • 注意区分预检请求和实际请求的处理

常见问题排查

问题1:预检请求被拦截

现象:OPTIONS请求返回403或404
解决:确保Spring Security允许OPTIONS请求通过

问题2:Cookie无法携带

现象:跨域请求无法携带认证信息
解决:设置allowCredentials(true),且不能使用通配符域名

问题3:自定义头部被拒绝

现象:请求头如X-Token无法发送
解决:在allowedHeaders中明确添加自定义头部

总结

CORS处理的核心思想是”全局兜底,局部特化”。通过合理的配置策略,既能保证开发效率,又能确保生产环境的安全性。记住,跨域访问的决定权始终在服务端,前端只是发起请求的一方。

在实际开发中,建议优先使用全局配置建立基础规则,然后根据具体业务需求使用@CrossOrigin注解进行精细化控制。这样既保持了配置的一致性,又提供了足够的灵活性。


Spring MVC 中的 CORS 与 Controller 局部处理实践
http://example.com/2025/01/14/SpringMVC跨域处理与Controller局部处理实践/
作者
chenji
发布于
2025年1月14日
许可协议