目标
浏览器控制台里的 CORS 报错只是一场看不见的协商的最终结果。浏览器先发携带 Access-Control-Request-Method 与 Request-Headers 的 OPTIONS 预检,再按严格算法核对响应。用 curl 复现这次预检,把不透明的报错变成可逐项核对的响应头清单,几秒内定位缺失项。
步骤要点
- 原样重放失败请求(带 Origin 头)确认基础连通性,普通 GET 返回 200 说明问题聚焦在预检环节。
- 手动构造 OPTIONS 预检:带上 Origin、Access-Control-Request-Method 与实际使用的 Request-Headers,观察响应。
- 对照响应中的 Access-Control-Allow-Methods 与 Allow-Headers,找出未被列出的请求头(如 x-api-key),它就是浏览器报错点名的对象。
- 在服务端补齐允许列表后,用一个未知 Origin 再测一次:正确实现应拒绝未知来源,证明允许列表确实在生效而非全放行。
排错提示
预检 200 但仍被拦截,多半是请求携带的自定义头没有出现在 Allow-Headers 里;带凭证的请求不允许通配符来源,必须回显精确 Origin 并设置 Allow-Credentials;只在部分路由生效说明 CORS 中间件挂载位置不对,应前移到全局。修复永远在服务端补允许项,而不是让客户端删掉合法请求头。
适用边界
curl 只能验证响应头是否齐全,无法执行浏览器最终的裁决逻辑,最终仍需浏览器验证一次;预检响应可能被缓存,排查时要留意 Access-Control-Max-Age 并清理缓存,否则会看到修复前的旧结果。
代码示例
curl -s -D - -o /dev/null -X OPTIONS "https://api.example.com/v1/search" \
-H "Origin: https://app.example.com" \
-H "Access-Control-Request-Method: POST" \
-H "Access-Control-Request-Headers: content-type,x-api-key"