一、跨域问题的本质:为什么浏览器要限制我们?
想象你住在A小区(域名),想借用B小区的健身房(资源)。但物业(浏览器)规定:除非两个小区属于同一开发商(同源),否则不允许跨小区借器材。这就是同源策略——浏览器保护用户数据的安全机制。
同源判断三要素(必须全部相同):
- 协议:http vs https
- 域名:www.example.com vs api.example.com
- 端口:80 vs 8080
常见跨域场景:
- 前端开发时本地3000端口请求后端8080端口
- 正式环境前端域名与API域名不同
- 使用CDN资源时协议不一致(http/https)
二、五大解决方案:如何合法跨小区借器材?
方案1:CORS
适用场景:正式环境、所有HTTP请求 原理:让B小区健身房在门口挂块牌子:A小区业主可进入(服务端设置响应头) 代码示例(后端Node.js):
res.header('Access-Control-Allow-Origin', 'https://your-frontend.com');
res.header('Access-Control-Allow-Methods', 'GET, POST');
方案2:代理服务器
适用场景:开发环境、不想改后端配置 原理:请住在A小区的快递员(同源服务)帮忙代取B小区的包裹 配置示例(webpack devServer):
devServer: { proxy: { '/api': 'http://backend-server.com' } }
方案3:JSONP
适用场景:仅限GET请求、老旧系统兼容 原理:通过纸条(script标签)传递消息,但只能传简单信息 代码示例:
function handleData(data) { console.log(data); }
const script = document.createElement('script');
script.src = 'http://api.example.com/data?callback=handleData';
document.body.appendChild(script);
方案4:Nginx反向代理
适用场景:生产环境、多服务整合 原理:让所有小区共用同一个物业入口(统一域名) 配置示例:
location /api/ {
proxy_pass http://backend-server.com;
}
方案5:临时通行证(PostMessage)
适用场景:iframe跨域通信 原理:安全协议 代码示例:
// 父窗口
iframe.contentWindow.postMessage('data', '*');
// 子窗口
window.addEventListener('message', e => {
if (e.origin === 'https://trusted.com') console.log(e.data);
});
三、避坑指南:这些错误千万别犯
- 不要用*通配符:Access-Control-Allow-Origin: *会暴露API给所有网站
- 小心Credentials:携带Cookie时需同时设置Access-Control-Allow-Credentials: true
- 预检请求陷阱:PUT/DELETE等复杂方法会触发两次请求(OPTIONS+实际请求)
- JSONP防XSS:必须验证回调函数参数,防止注入