应按http方法差异化配置cors响应头:对options预检请求显式声明allow-methods和allow-headers并返回204,用map指令动态映射各方法允许的权限;真实请求中依方法暴露必要响应头,带凭证时禁止使用通配符且须精确匹配源与头。

针对不同 HTTP 方法配置差异化的 CORS 响应头,核心在于区分“简单请求”与“预检请求”,并让 Nginx 在 OPTIONS 预检阶段和实际请求阶段分别注入对应权限——不能一概而用通配符,也不能把所有头都无差别加给所有方法。
区分预检请求(OPTIONS)与真实请求
浏览器只对非简单请求(如 PUT、DELETE、带 Content-Type: application/json 的 POST)发起预检。此时 Nginx 必须拦截 OPTIONS 并返回明确的 Access-Control-Allow-Methods 和 Access-Control-Allow-Headers,但不转发给后端。
-
OPTIONS响应中必须声明允许的方法列表(如GET, POST, PUT, DELETE),不能写* -
Access-Control-Allow-Headers必须显式列出前端实际发送的自定义头(如Authorization、X-Request-ID),不能用*(除非不带凭证) - 预检响应必须返回
204或200,且需带Content-Length: 0和Content-Type: text/plain
按方法动态控制 Access-Control-Allow-Methods
不能对所有请求硬写死同一组方法。比如 GET /api/status 可能只需读权限,而 POST /api/users 需写权限,DELETE /api/users/123 更需严格校验。
- 用
map指令按$request_method映射允许的方法字符串:
map $request_method $cors_methods {
default "GET, HEAD";
POST "GET, POST, OPTIONS";
PUT "GET, PUT, OPTIONS";
DELETE "DELETE, OPTIONS";
} - 在
location中使用:add_header 'Access-Control-Allow-Methods' $cors_methods always; - 注意:该头仅在预检响应中生效;真实请求响应中浏览器不校验它,但规范要求仍需返回
按方法决定是否暴露敏感响应头
Access-Control-Expose-Headers 控制前端 JS 能读取哪些响应头。不是所有头都该暴露,尤其涉及权限或调试信息的头(如 Set-Cookie、Server、X-Debug-Token)。
- 对
GET类查询接口,可暴露分页相关头:Content-Range、X-Total-Count - 对
POST创建资源,可额外暴露Location(指向新资源 URL) - 对
DELETE或无返回体的操作,通常无需暴露额外头,设为空或仅Content-Length - 避免暴露
WWW-Authenticate、Set-Cookie等敏感字段
带凭证请求必须方法与源双重绑定
一旦启用 Access-Control-Allow-Credentials: true,就禁止使用 * 作为 Access-Control-Allow-Origin,且 Access-Control-Allow-Methods 和 Access-Control-Allow-Headers 也必须精确匹配——否则浏览器直接拒绝。
- 只在确实需要 Cookie 或 Authorization 的路径下开启凭证支持(如
/api/auth/) - 配合白名单
map $http_origin $cors_origin,确保$cors_origin非空时才添加Allow-Credentials - 例如:
if ($cors_origin) { add_header 'Access-Control-Allow-Credentials' 'true' always; } - 若某方法(如
OPTIONS)未携带凭证,但后续POST需要,则预检响应中仍需包含该头,否则浏览器判定不一致而失败











