最后更新:2026-02-22
跨域应该是前端面试被问烂了的话题,工作里也几乎每个项目都会遇到。但很多人只记得”配 CORS 头”或者”用代理”,问起背后的原因,往往说不清楚。
我把这个问题从头梳理一遍。
为什么会有跨域
浏览器有一个安全机制叫同源策略(Same-Origin Policy)。「同源」的定义是:协议、域名、端口三者完全相同。
| 对比 | 同源? |
|---|---|
http://a.com vs https://a.com |
❌ 协议不同 |
http://a.com vs http://b.com |
❌ 域名不同 |
http://a.com:80 vs http://a.com:3000 |
❌ 端口不同 |
http://a.com/page1 vs http://a.com/page2 |
✅ 同源 |
同源策略规定:非同源的页面之间,不能互相读取对方的 Cookie、LocalStorage,也不能操作对方的 DOM,更重要的是——不能发送 Ajax 请求到非同源的地址。
这是浏览器对用户的保护,防止恶意网站偷你的数据。
CORS:服务端开门
CORS(Cross-Origin Resource Sharing,跨域资源共享)是目前最主流的跨域解决方案。本质是:服务端在响应头里声明「我允许谁来访问」。
简单请求
满足以下条件的是简单请求:
- 方法是 GET、POST 或 HEAD
- Content-Type 是
text/plain、application/x-www-form-urlencoded或multipart/form-data
简单请求只需要服务端设置一个响应头:
1 | Access-Control-Allow-Origin: https://your-frontend.com |
预检请求(Preflight)
不满足简单请求条件的(比如用了 PUT/DELETE,或者 Content-Type 是 application/json),浏览器会先发一个 OPTIONS 请求问服务器「你允许我这么请求吗」,服务器回答允许后,才发真正的请求。
服务端需要处理 OPTIONS 请求:
1 | Access-Control-Allow-Origin: https://your-frontend.com |
Node.js/Express 里通常用 cors 中间件:
1 | const cors = require('cors') |
注意:如果前端请求需要带 Cookie(withCredentials: true),服务端的 Access-Control-Allow-Origin 不能设为 *,必须指定具体域名,同时要加 Access-Control-Allow-Credentials: true。
开发环境:代理转发
CORS 需要改服务端,但有时候后端不是你负责的,或者你在调第三方接口,改不了服务端。这时候开发环境最常用的方案是代理。
代理的原理:让同域的本地开发服务器转发请求,浏览器看到的是同域请求,不触发跨域限制。
Vite 配置代理:
1 | // vite.config.js |
webpack/CRA 配置代理:
1 | // src/setupProxy.js(Create React App) |
这个只在开发环境有效,代理服务器和前端同域。生产环境需要用 Nginx 做反向代理。
生产环境:Nginx 反向代理
生产环境最常见的方案是前端和后端都挂在 Nginx 下,通过 Nginx 转发:
1 | server { |
这样前端访问 your-domain.com/api/users,Nginx 转发到后端,浏览器看到的始终是同一个域,没有跨域。
JSONP:了解就好,别用了
JSONP 是老方案,原理是利用 <script> 标签不受同源限制:
1 | function jsonp(url, callback) { |
服务端返回的不是 JSON,而是一个函数调用:jsonp_1234567890({...})。
缺点很明显:只能 GET 请求,有 XSS 风险,已经很少用了。面试提一下原理就行。
postMessage:跨窗口通信
如果是两个不同源的页面(比如主页面和 iframe)需要通信,用 postMessage:
1 | // 发送方 |
总结一下选哪种方案
| 场景 | 推荐方案 |
|---|---|
| 能改服务端 | 配置 CORS 响应头 |
| 开发环境调后端接口 | 本地 devServer 代理 |
| 生产环境前后端分离部署 | Nginx 反向代理 |
| 调第三方不能修改的接口 | 自建中间层服务做代理 |
| 两个页面/iframe 通信 | postMessage |
遇到跨域问题别慌,先判断是开发环境还是生产环境,再看能不能改服务端,然后按上面的方案选一个。





