07 CORS Header 详解与速查
1. 请求方 Header
Origin
浏览器声明发起请求的页面源:
Origin: https://www.example.com
它只有源,没有路径。服务端可用它选择 CORS 响应,但不可把它当作身份凭据。
Access-Control-Request-Method
仅用于预检,说明正式请求准备使用的方法:
Access-Control-Request-Method: PATCH
Access-Control-Request-Headers
仅用于预检,列出正式请求准备携带的非简单 Header:
Access-Control-Request-Headers: authorization,content-type,x-request-id
2. 响应方 Header
Access-Control-Allow-Origin
Access-Control-Allow-Origin: https://www.example.com
表示浏览器可以让该源读取响应。值通常是一个具体 Origin 或 *,不是以逗号分隔的来源列表。多个来源要在服务端匹配请求的 Origin,再回显唯一匹配值。
* 适合真正公开、无需凭据的资源。它不代表认证或授权,也不能与浏览器凭据模式组合使用。
Access-Control-Allow-Credentials
Access-Control-Allow-Credentials: true
允许浏览器向跨源请求携带凭据,并向页面暴露带凭据响应。只有 true 是有效允许值。使用它时:
- 服务端必须返回明确 Origin,不能返回
*; - Fetch 要配置
credentials: "include",Axios 要配置withCredentials: true; - Cookie 还受
SameSite、Secure、Domain 等规则约束; - Cookie 登录接口仍需 CSRF 防护。
JWT Bearer Token 是显式请求头,不属于 Fetch credentials 开关所指的 Cookie 凭据模式;但 Authorization 会触发预检,必须被允许。
Access-Control-Allow-Methods
Access-Control-Allow-Methods: GET,HEAD,POST,PUT,PATCH,DELETE
在预检响应中声明允许的正式请求方法。它不是 Express 路由权限:即便列出 DELETE,DELETE 路由仍须认证、授权和参数校验。
Access-Control-Allow-Headers
Access-Control-Allow-Headers: Authorization,Content-Type,X-Request-Id
在预检响应中声明正式请求可携带的 Header。只表示浏览器可以发送,并不表示 Authorization 内容有效。
cors 中间件未显式配置 allowedHeaders 时,通常会根据浏览器的 Access-Control-Request-Headers 生成响应。生产项目也可以明确列出,以便审计。
Access-Control-Expose-Headers
跨源页面默认只能读取一小组安全列出的响应头。需要前端读取下载文件名、请求 ID 等信息时显式暴露:
Access-Control-Expose-Headers: Content-Disposition,X-Request-Id,X-Total-Count
它不是“把 Header 发给浏览器”:Header 原本已经抵达浏览器;它决定 JavaScript 的 response.headers 能否读取。
Access-Control-Max-Age
Access-Control-Max-Age: 600
允许浏览器缓存预检结果若干秒,减少 OPTIONS。浏览器可能设置自身上限。配置太长会使 CORS 策略变更不能立刻反映到已有客户端,因此初期可采用几分钟并逐步调整。
3. Vary: Origin 为什么重要
当服务器按 Origin 动态响应时:
Access-Control-Allow-Origin: https://a.example.com
Vary: Origin
Vary: Origin 告诉 CDN、Nginx 缓存或其他共享缓存:不同 Origin 对应不同响应版本。缺失它可能导致为 A 站生成的响应被缓存后错误地交给 B 站。
Vary 是可组合 Header。不要用 res.set("Vary", "Origin") 粗暴覆盖已有值;Express 可使用:
res.vary("Origin");
预检若根据请求 Header 动态响应,还可能出现:
Vary: Origin, Access-Control-Request-Headers
通常应让成熟的 CORS 中间件正确处理,而不是手写一组响应头。
4. Header 出现在哪个响应
| Header | 简单/正式响应 | 预检响应 |
|---|---|---|
Access-Control-Allow-Origin |
是 | 是 |
Access-Control-Allow-Credentials |
需要凭据时 | 需要凭据时 |
Access-Control-Allow-Methods |
通常不必 | 是 |
Access-Control-Allow-Headers |
通常不必 | 是 |
Access-Control-Expose-Headers |
是 | 通常不必 |
Access-Control-Max-Age |
否 | 是 |
5. 常见误区
Allow-Origin不是服务器访问控制名单。Allow-Headers: Authorization不是自动通过 JWT。Expose-Headers与允许请求携带哪些 Header 是两回事。- 浏览器报 CORS 错误时,真实原因也可能是 502、TLS 失败或重定向响应缺少 CORS Header。
- 不要同时由 Nginx 和 Express 生成互相不同的 CORS Header。