网络cors站
去年夏天,网络朋友让我帮他查一个物流单号。网络他给我发了个链接,网络我点开一看,网络浏览器直接跳出一行红字:“已拦截跨源请求:同源策略禁止读取位于 https://api.example.com/track 的网络远程资源。”页面白屏,网络什么也看不到。网络他急了,网络说这网站平时好好的网络,怎么今天不行。网络我让他打开控制台,网络果然,网络CORS 报错赫然在列。网络
这就是网络 CORS 站最典型的样子——不是网站挂了,是网络浏览器在中间拦了一道。很多人第一次遇到这种情况会以为是服务器崩了,或者自己网络有问题,其实都不是。浏览器在替你做安全决策,它觉得这个请求“跨源”了,得先问问服务器同不同意。
所谓“跨源”,简单说就是协议、域名、端口三者有一个对不上。你从 http://localhost:3000 去请求 https://api.xxx.com/data,协议不同、域名不同、端口不同,浏览器立刻警觉:这俩不是一个地方的,默认不让你读响应内容。注意,请求其实发出去了,服务器也处理了,但浏览器把返回的数据扣下了,不交给你的 JavaScript 代码。这就是为什么在 Network 面板里能看到 200,但代码里拿不到数据。
那服务器怎么“同意”呢?靠响应头。最常见的是 Access-Control-Allow-Origin。服务器返回这个头,值设为 * 或者具体的源,浏览器一看,哦,允许,就把数据放行。如果这个头缺失,或者值不匹配,浏览器就报错。我见过不少后端开发图省事,直接写 *,结果前端要带 Cookie 的时候又不行了——因为 * 和 credentials: 'include' 不能共存。这时候得把源写死,还得加上 Access-Control-Allow-Credentials: true。
预检请求是另一个让人头疼的东西。不是所有跨源请求都直接发。如果请求方法不是 GET、HEAD、POST,或者 Content-Type 是 application/json 而不是那几个“简单”类型,浏览器会先发一个 OPTIONS 请求探路。这个 OPTIONS 不带业务数据,只问服务器:我能不能用 PUT?能不能带 Authorization 头?服务器得用 Access-Control-Allow-Methods 和 Access-Control-Allow-Headers 回应。很多后端框架默认不处理 OPTIONS,结果预检就挂了,真正的请求根本发不出去。我调试过最久的一次 CORS 问题,就是后端路由把 OPTIONS 请求当成了未定义方法,直接 405。
有人问,那我用代理不就行了?开发阶段用 webpack 或者 vite 的 proxy,把请求转发到同源路径下,浏览器就不跨源了。这招确实管用,但只限本地。上线之后,前端静态资源和 API 往往不在同一个域名,CORS 该配还得配。还有人用 Nginx 反向代理,把 API 路径挂到前端域名下,本质上也是绕开跨源限制。这些办法都行,但得清楚自己在干什么——不是 CORS 消失了,是你把跨源变成了同源。
我自己的习惯是,遇到 CORS 报错先看三件事:请求有没有发出去?响应头里有没有 Access-Control-Allow-Origin?如果是预检失败,OPTIONS 请求返回了什么?这三步能解决八成问题。剩下两成,多半是缓存或者中间层搞的鬼——CDN 把响应头吞了,或者网关重写了头。那种情况就得一层一层剥。
说到底,CORS 不是 bug,是浏览器的一种保护机制。它烦人,但没它更可怕。你总不希望随便一个网页就能偷偷读你银行后台的数据吧。理解它的规则,比骂它有用得多。