ARTICLE DETAIL

资讯详情

深耕网站SEO优化与搜索引擎排名提升的一线实战洞察。

理解 CORS:浏览器为什么拦你

理解 CORS:浏览器为什么拦你 CORSCross-Origin Resource Sharing跨源资源共享是浏览器的一套规则页面所在源与接口所在源不同时是否允许前端脚本读取这次响应。控制台里最常见的红字之一就是某请求被 CORS 策略挡住。很多人一看到就改前端fetch乱加 header或随手把服务端改成Access-Control-Allow-Origin: *。症状能暂时消失根因却没弄清。下面按「浏览器在防什么 → 什么算跨源 → 简单请求与预检 → 怎么正确放行」说明。一、先说一个具体麻烦页面在https://app.example.com接口在https://api.example.com。用fetch调接口Network 面板里请求可能已经到了服务器甚至返回了 200。但前端代码读不到 body控制台报 CORS error。这让人很困惑服务器明明成功了为什么还算失败因为 CORS 主要约束的是浏览器里的前端脚本能不能读取跨源响应不是禁止服务器处理请求。curl、服务端对服务端调用通常不受这套规则限制。二、核心思路同源才默认信任浏览器默认假定不同源的网站不应随便读你的接口结果。否则任意恶意页都可能拿着你的登录态去别的站拉数据。所谓源origin通常由三部分组成协议、主机、端口。任一不同就是跨源。举例来说1https://example.com与https://api.example.com→ 跨源主机不同2http://example.com与https://example.com→ 跨源协议不同3https://example.com与https://example.com:8443→ 跨源端口不同4https://example.com与https://example.com/app→ 同源路径不算进源CORS 就是跨源时的「通行证」协议服务端用响应头声明「我允许哪个源的前端读我」。三、谁在拦拦的是什么记住三句排障会快很多。1拦的是浏览器中的前端 JS 读取不是 TCP 一定发不出去2很多「简单请求」会先发出去若响应缺允许头JS 仍读失败3「非简单请求」会先发 OPTIONS 预检预检不过正式请求可能根本不发所以不要只看 Network 有没有 200还要看响应头是否包含合适的Access-Control-Allow-Origin等字段以及控制台的 CORS 原文。四、简单请求与预检4.1 简单请求大致直觉方法是 GET / HEAD / POST且头集合比较「朴素」例如普通Content-Type为application/x-www-form-urlencoded、multipart/form-data、text/plain等。细节以规范为准日常记住一旦加了自定义头、或 JSON 的Content-Type: application/json常常就不再「简单」。4.2 预检preflight浏览器先发OPTIONS询问允不允许这个源、用这个方法、带这些头来访问服务端需要用响应头回答常见包括1Access-Control-Allow-Origin2Access-Control-Allow-Methods3Access-Control-Allow-Headers4可选Access-Control-Max-Age预检缓存多久下面是一个预检响应的示意。HTTP/1.1 204 No Content Access-Control-Allow-Origin: https://app.example.com Access-Control-Allow-Methods: GET, POST, PUT, DELETE Access-Control-Allow-Headers: Content-Type, Authorization Access-Control-Max-Age: 7200上面代码中允许源必须对得上你的前端页方法和自定义头要覆盖真实请求。少写一个自定义头预检就会失败。五、带 Cookie 时更严若前端要带上 cookiecredentials: include服务端不能再用Access-Control-Allow-Origin: *必须回显具体源并加上Access-Control-Allow-Credentials: true同时前端也要显式开 credentials。三边任一不一致表现为「登录态带不上」或继续 CORS 报错。下面是前端侧最小示例。awaitfetch(https://api.example.com/me,{method:GET,credentials:include,})上面代码中credentials: include要求服务端按「具体源 Allow-Credentials」放行只改前端、不改服务端头解决不了。六、排障清单我按这个顺序查1是否真的跨源看协议 / 主机 / 端口2失败发生在预检还是正式请求看有没有 OPTIONS3Allow-Origin是*还是具体源是否匹配当前页4是否带凭证头组合是否合法5自定义头 / 方法是否出现在Allow-Headers/Allow-Methods6网关、CDN、反向代理有没有把 OPTIONS 或 CORS 头吃掉本地开发常见做法是开发服务器代理到 API同源相对路径生产再由网关统一加 CORS。这样能减少「本地一套、线上一套」的混乱但生产仍要明确允许哪些源。七、常见误区1以为 CORS 是服务器防火墙服务器可能已 200是浏览器不让 JS 读。2前端用插件「关掉 CORS」当修复那只是改了你自己的浏览器用户环境不会跟着改。3生产环境长期Allow-Origin: *且还带 cookie规范不允许这种组合即使绕过安全模型也被挖空。4只配了正式请求头忘了 OPTIONS预检死在网关上正式业务代码永远触达不到。5把鉴权错误当成 CORS401/403 与 CORS 失败不同。先分清控制台文案是 CORS 还是 HTTP 状态问题。八、小结CORS 是浏览器在跨源时要求服务端明确授权前端脚本读取响应的机制。它拦的是「前端能不能读」不是「服务器能不能算」。修好它靠的是源判断、预检头、凭证规则对齐而不是在前端玄学地多加几个 header。下次再看见红字先问跨源了吗预检过了吗Allow-Origin 写对了吗完
返回列表