CORS配置文件
可以。结合浏览器侧的 CORS 标准说明和 Spring 官方文档,常见配置项基本可以分成两层来看:
一层是HTTP/CORS 规则本身,也就是浏览器认哪些响应头。另一层是Spring 里的配置 API,比如allowedOrigins、allowedMethods,它们本质上是在生成这些 CORS 响应头。CORS 是一种基于 HTTP 头的机制;当请求属于“非简单请求”时,浏览器会先发一个OPTIONS预检请求,确认服务端是否允许真正的跨域请求。(MDN文档)
你现在最关心的,可以按下面这些项理解。
1. 允许哪些来源:allowedOrigins/Access-Control-Allow-Origin
这是最核心的一项,表示哪些前端来源可以访问后端资源。浏览器看的是响应头Access-Control-Allow-Origin。它可以是某个明确的源,例如http://localhost:5173,也可以是*表示任意源。MDN 还特别提醒:当返回的是具体 origin 而不是*时,响应通常应同时带上Vary: Origin,这样缓存才不会把某个来源的结果错误复用给别的来源。(MDN文档)
在 Spring 里,对应的是allowedOrigins(...);Spring 的CorsRegistration和CorsConfiguration都把它定义为“允许浏览器发起跨域请求的来源列表”。(Home)
实际作用很好理解:
- 只允许你的前端地址访问后端
- 防止随便一个别的站点也能直接拿到接口响应
2. 允许哪些 HTTP 方法:allowedMethods/Access-Control-Allow-Methods
这项表示跨域请求允许使用哪些方法,例如GET、POST、PUT、DELETE、OPTIONS。对预检请求来说,浏览器会先问:“我等下想用某种方法发请求,行不行?” 服务端就要通过Access-Control-Allow-Methods告诉浏览器哪些方法被允许。MDN 里明确列出,如果预检阶段在这个头里找不到目标方法,浏览器就会判定失败。(MDN文档)
所以你前面遇到的情况就很典型:配置里没放OPTIONS,预检直接被拦,浏览器报 CORS 错。Spring 文档也说明它支持配置允许的方法列表。(Home)
3. 允许哪些请求头:allowedHeaders/Access-Control-Allow-Headers
这项表示前端真实请求里允许带哪些自定义请求头。常见的就是:
AuthorizationContent-TypeX-Requested-With
对于预检请求,浏览器会把自己准备发送的头放在Access-Control-Request-Headers中;如果服务端没有在Access-Control-Allow-Headers里允许这些头,浏览器就不会继续发真实请求。MDN 明确说了:当预检请求带有Access-Control-Request-Headers时,这个响应头是必需的。(MDN文档)
这也是很多“登录成功,但带 token 的接口失败”的另一常见根因:不是方法没放行,而是Authorization头没放行。Spring 中对应allowedHeaders(...)。(Home)
4. 是否允许携带凭证:allowCredentials/Access-Control-Allow-Credentials
这项表示浏览器是否可以在跨域请求中携带凭证,例如:
- Cookie
- HTTP 认证信息
- 某些带凭据的请求上下文
MDN 说明得很清楚:Access-Control-Allow-Credentials的有效值只有true;如果需要凭证但服务端没返回这个头,浏览器会报网络错误。它还强调了一个很重要的限制:当允许凭证时,Access-Control-Allow-Origin不能用*。(MDN文档)
在 Spring 里,对应allowCredentials(...)。这项经常用于:
- 前后端分离但仍用 Cookie 会话
- 需要跨域发送认证信息的场景
如果你们前端是用Authorization: Bearer xxx,这通常更多和allowedHeaders、预检放行相关;如果是 Cookie 登录态,则allowCredentials(true)更关键。Spring 文档也提到,像allowCredentials和maxAge这类单值属性,局部配置会覆盖全局配置。(Home)
5. 预检结果缓存多久:maxAge/Access-Control-Max-Age
这项表示浏览器可以把预检结果缓存多长时间,单位通常是秒。意思是:在缓存有效期内,浏览器不必每次都先发一遍OPTIONS,性能会更好。Spring 官方文档把它作为 CORS 常见配置项之一;CorsConfiguration也明确提供了maxAge相关设置。(Home)
它的作用主要是减少预检开销,尤其是接口调用频繁的时候。
6. 允许前端读取哪些响应头:exposedHeaders/Access-Control-Expose-Headers
默认情况下,浏览器并不会把所有响应头都暴露给前端 JS。
如果你希望前端通过fetch或axios读取某些响应头,比如:
Content-DispositionX-Trace-IdX-Total-Count
就要通过Access-Control-Expose-Headers显式暴露。Spring 里对应exposedHeaders(...),Spring 官方把它列为标准 CORS 配置项之一。(Home)
它的作用是:后端虽然返回了头,但前端 JS 默认未必能读到;暴露后才能读。
7. 允许的来源模式:allowedOriginPatterns
这是 Spring 里的一个增强项,不是浏览器 CORS 头的名字,而是 Spring 为了方便配置提供的模式匹配能力。CorsRegistration官方 API 里明确说明了allowedOriginPatterns(...),并指出如果同时设置了allowedOriginPatterns,它会优先生效。(Home)
它适合这种场景:
- 本地开发多个端口
- 一批子域名要放行
- 不想一个个把 origin 写死
和allowedOrigins的区别是:
allowedOrigins更适合精确列举allowedOriginPatterns更适合模式匹配
8. 全局配置与局部配置
Spring 官方文档说明,CORS 可以做全局配置,也可以做局部配置;一般规则是多数属性会做叠加,但像allowCredentials、maxAge这类单值属性,局部会覆盖全局。(Home)
这在实际项目里很重要,因为经常会出现:
- 全局允许一组前端域名
- 某个接口单独再收紧或放宽规则
9. 一个常见误区:只配 methods,不配 headers
你前面的案例就是最容易踩坑的组合之一。很多人会写:
.allowedMethods("GET","POST","PUT","DELETE")但如果真实请求带:
Authorization- 或特殊
Content-Type
那只配 methods 还不够,还要确保:
OPTIONS放行Authorization在allowedHeaders里被允许- 如果走 Cookie,会话类场景还要考虑
allowCredentials。这些都是浏览器 CORS 机制和 Spring 官方配置模型共同要求的。(MDN文档)
一个实战层面的理解框架
可以把常见配置项记成这 6 个问题:
谁能来?
allowedOrigins/allowedOriginPatterns能用什么方法来?
allowedMethods请求里能带什么头?
allowedHeaders能不能带凭证?
allowCredentials前端能读哪些响应头?
exposedHeaders预检结果缓存多久?
maxAge
一个常见的 Spring 配置示意
只作为理解示意:
registry.addMapping("/**").allowedOrigins("http://localhost:5173").allowedMethods("GET","POST","PUT","DELETE","OPTIONS").allowedHeaders("Authorization","Content-Type").exposedHeaders("Content-Disposition").allowCredentials(true).maxAge(3600);这段的语义就是:
- 允许
http://localhost:5173调你 - 允许这些方法,包括预检用的
OPTIONS - 允许前端带
Authorization、Content-Type - 允许前端读取
Content-Disposition - 允许携带凭证
- 预检结果缓存 1 小时
