CORS
同源策略、预检;对照 Spring CORS。
25 分钟
CORS
浏览器 同源策略 默认禁止 https://app.example.com 的 JavaScript 读取 https://api.example.com 的响应——即使 API 本身对 curl 完全开放。CORS(Cross-Origin Resource Sharing) 是服务器通过 响应头 声明「哪些跨域前端可以读我的响应」。后端工程师必须分清:CORS 不是认证,它 不阻止 非浏览器客户端直接调 API。
学习目标
- 说清「简单请求」与「预检 OPTIONS」的差异
- 在 Spring Boot 中配置 CORS,并与 http-cors 协议细节对照
- 避免
Access-Control-Allow-Origin: *与凭据携带的组合陷阱
同源是什么
协议 + 域名 + 端口 三者相同才同源:
| 页面来源 | API | 是否跨域 |
|---|---|---|
https://a.com | https://a.com/api | 否 |
https://a.com | https://api.a.com | 是 |
http://a.com:3000 | http://a.com:8080 | 是(端口不同) |
Postman、服务器间调用不受 CORS 限制——所以 API 仍要 认证与授权(sb-security)。
简单请求 vs 预检
简单请求(如 GET、部分 POST):浏览器直接发,服务器用响应头决定是否允许前端 JS 读 body。
预检请求:带自定义头、PUT/DELETE、非简单 Content-Type 等时,浏览器 先发 OPTIONS:
OPTIONS /api/users HTTP/1.1
Origin: https://app.example.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: Authorization, Content-Type
服务器应返回:
Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Headers: Authorization, Content-Type
Access-Control-Max-Age: 86400
Spring @CrossOrigin 或 CorsConfigurationSource 需 正确处理 OPTIONS,否则前端报 CORS 错误但 curl 正常——典型「只有浏览器坏」问题。
Spring Boot 配置示例
@Configuration
public class CorsConfig {
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**")
.allowedOrigins("https://app.example.com")
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
.allowedHeaders("Authorization", "Content-Type")
.allowCredentials(true)
.maxAge(3600);
}
};
}
}