我们总会碰到的问题—跨域

46 阅读2分钟

一、跨域问题的本质:为什么浏览器要限制我们?

想象你住在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:必须验证回调函数参数,防止注入