跨域(CORS)是什么?一文读懂前端最头疼的跨域报错
你本地跑得好好的前端页面,一调后端接口就弹出 Access-Control-Allow-Origin 相关的红色报错,接口返回 200 却拿不到数据。这是几乎每个前端新手都会撞上的墙。跨域(CORS)的核心答案先给出来:它是浏览器出于安全考虑,默认禁止网页去请求「和自己来源不同」的接口的一种保护机制;报错不是后端挂了,而是浏览器把响应拦了下来。今天这篇文章,编程狮就用最通俗的比喻把它讲透。
本文基于现代浏览器与 HTTP 协议验证,覆盖同源策略的原理、CORS 的响应头机制、常见跨域报错的解法,以及开发环境最省事的代理方案。看完你不但能看懂那条红色报错在说什么,还能知道该找谁、怎么改。
一、一句话说清什么是跨域
跨域指的是:你当前网页的「来源」和你要请求的「目标地址」不一致。这里的来源由三部分锁定——协议、域名、端口,三者有一个不同,浏览器就判定为跨域。比如你的页面在 http://localhost:3000,却去请求 https://api.example.com,协议不同、域名不同,于是跨域。
把来源想象成门牌号:协议是小区(http/https),域名是楼栋(example.com),端口是房间号(3000/8080)。只要有一项对不上,浏览器就认为「你去了别人家」,于是启动保护。同源策略是这套保护的总规则,CORS 则是在规则里开的「通行证」。
举个最直接的例子:http://a.com:3000 和 https://a.com:3000 跨域(协议不同);http://a.com 和 http://www.a.com 跨域(域名不同,www 也算不同主机);http://a.com:3000 和 http://a.com:8080 也跨域(端口不同)。只有三者完全一致,浏览器才当作同源放行。很多人排查半天,最后发现只是端口写错了一位。
💡 小提示:很多人误以为跨域是后端接口挂了。其实接口往往正常返回了,只是浏览器看完响应头发现「没有放行许可」,才把数据扣下不交给你的 JS。
二、同源策略:浏览器为什么要拦你
同源策略(Same-Origin Policy)是浏览器从一开始就定下的铁律:一个网页里的脚本,只能读取和它同源的资源。它的初衷是防止恶意网站偷偷拿着你的登录态去攻击别的站点——比如你登录了银行,又打开了一个坏网站,坏网站若能动用你的银行接口,后果不堪设想。
所以浏览器不是故意和你作对,而是在替你挡风险。前端报错里最让人头秃的,往往就是这种「请求发出去了、后端也回了、可我就是拿不到」的跨域拦截。理解了它保护的是什么,你就不会再把它当成玄学。
同源策略管得很宽:Cookie、DOM、接口数据都在它的防护范围内。平时你感觉不到它,是因为大多数页面只和自己的同源后端打交道;一旦前后端分离、域名不同,它立刻就跳出来。
一个常见的连带影响是 Cookie:同源策略下,脚本只能读取自己来源下的 Cookie,跨域请求的 Cookie 默认也不会自动带上。所以即使接口通了,如果你的登录态是靠 Cookie 传递的,跨域场景还得额外处理凭证,这也是为什么单纯加了 CORS 头有时还不够。
三、CORS 到底是什么:预检与响应头
CORS(跨源资源共享)是官方给出的「合法放行」方案:后端在响应里带上特定的 HTTP 头,告诉浏览器「这个接口允许谁跨域访问」。最关键的头是 Access-Control-Allow-Origin。
HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://your-site.com
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: Content-Type
上面这段响应头的意思是:只允许 https://your-site.com 这个来源跨域访问,且支持指定的方法和请求头。浏览器看到这一行,就放心把数据交给前端。关于 HTTP 响应头和状态码的完整机制,HTTP 教程 里讲得更系统。
还有一类「预检请求」(preflight):当你的请求带自定义头、或用 PUT/DELETE 这类非简单方法时,浏览器会先悄悄发一个 OPTIONS 请求去问「我能不能跨域」,后端同意了才发真正的请求。很多人没处理 OPTIONS,于是卡在预检这一步。
补充一个容易踩的点:如果你的请求需要携带 Cookie 等凭证,前端要设 fetch 的 credentials: 'include',后端还要额外返回 Access-Control-Allow-Credentials: true,且此时 Allow-Origin 不能再用 *,必须写明确的来源。凭证和通配符二者不可兼得,这是 CORS 里最常被忽略的一条。
四、常见跨域报错与对应解法
前端报错虽然千奇百怪,落到解法上基本是三条路,按场景选:
| 场景 | 报错特征 | 解法 |
|---|---|---|
| 后端是你自己的 | No 'Access-Control-Allow-Origin' |
后端加响应头放行 |
| 只在本机联调 | 本地 3000 调 8080 被拦 | 开发服务器配代理 |
| 老系统不支持头 | 改不了后端 | 用 JSONP 或网关中转 |
顺带说下表格里的 JSONP:它是 CORS 普及前的老办法,利用 <script> 标签不受同源限制的特性,让后端把数据包装成函数调用返回。它只能发 GET 请求、且依赖后端配合改写返回格式,今天已很少新项目使用,只在改不了老后端时作为兜底方案。
第一种,后端加头最直接。以 Node.js + Express 为例:
// 在路由前统一加响应头
app.use((req, res, next) => {
res.setHeader('Access-Control-Allow-Origin', 'https://your-site.com');
res.setHeader('Access-Control-Allow-Methods', 'GET,POST,PUT,OPTIONS');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
next();
});
上面这段做的是在每次响应前写入 CORS 头,让浏览器放行。想用 Express 写这类接口,Node.js 教程 可以补一下服务端基础。前端发请求时直接用 fetch 即可,无需特殊配置,浏览器会自动带上跨域逻辑。
⚠️ 注意:生产环境不要图省事把
Access-Control-Allow-Origin设成*(允许任意来源),那等于把保护门焊死,存在凭证泄露风险。只允许明确的可信来源才是正确做法。
五、开发环境用代理最省事
如果你只是本地联调,最干净的办法不是改后端,而是让「前端和后端看起来同源」。开发服务器(如 Vite、webpack-dev-server)都支持配置代理:把 /api 开头的请求转发到真实后端,浏览器只看到同源的请求,自然不再报跨域。
// vite.config.js 里的代理示例
export default {
server: {
proxy: {
'/api': 'http://localhost:8080'
}
}
}
这段配置把本地 /api 请求代理到 8080 端口的真实服务,开发时你访问的还是 localhost:3000,浏览器认为同源,跨域问题就地消失。等上线时再由后端统一加 CORS 头,前后端各司其职。前端发请求的基础在 JavaScript 教程 的 fetch 章节,建议顺手练熟。
六、总结:记住这三句话
一句话收束:跨域是浏览器的安全保护,不是后端故障;CORS 是后端用响应头发的「通行证」;本地联调用代理最省事。把这三句记牢,下次再看到那条红色报错就不会慌。
要点带走:
- 协议、域名、端口任意一个不同,就是跨域;
- 报错时先看响应头有没有
Access-Control-Allow-Origin,没有就是后端没放行; - 生产靠后端加头,开发靠代理,别在生产环境用
*放行。
理解同源策略和 CORS,是前端联调的基本功,搞懂它能省下大量无效排查时间。
延伸学习
想把前后端联调这条路走顺,可以按这个顺序来:
- 先把 HTTP 教程里请求头、响应头、状态码的部分过一遍,理解浏览器和服务器怎么对话;
- 前端发请求的基础在 JavaScript 教程的 fetch 章节,建议顺手练熟;
- 想系统入门整条前端路线,前端开发零基础到项目实战 是边学边练的形式,适合巩固;
- 不知道从哪门语言切入,可以看看 前端开发方向 给出的体系地图。
常见问题
Q:为什么接口返回 200 我还是拿不到数据?
A:因为被浏览器拦截了。后端确实回了 200,但响应头里没有合法的 CORS 放行信息,浏览器出于同源策略把数据扣下、不交给你的 JS,所以代码里读不到。补上 Access-Control-Allow-Origin 即可。
Q:本地调接口一定要后端改代码吗? A:不一定。如果只是本机开发联调,在开发服务器里配代理把请求转发到真实后端,让浏览器认为是同源请求,就能绕开跨域,不必动后端。
Q:Access-Control-Allow-Origin 设成星号为什么不好? A:星号表示允许任意网站跨域访问你的接口,等于放弃了来源限制,配合携带凭证的场景会带来安全风险。正确做法是只填明确可信的来源地址。

免费 AI IDE



