前端解决跨域的方案有哪些

前言

前后端分离与浏览器安全限制使得跨域成为前端开发绕不过的问题。目前跨域对开发最大的影响是本地开发请求服务器资源,生产环境多数已经通过CORS配置好。跨域是前后端对接数据的第一道坎,也是比较能考验web开发合作经验的一个问题。

什么是跨域(Cross-Origin)?

跨域(Cross-Origin)是指浏览器出于安全考虑,限制了来自不同 源(Origin) 的 JavaScript 代码访问资源的权限。

1. 什么是“同源”?

浏览器的 同源策略(Same-Origin Policy, SOP) 规定,只有当两个 URL 的 协议(Protocol)、域名(Domain)、端口(Port) 完全一致时,才属于同源,否则就是跨域。

URL AURL B是否同源原因
https://example.comhttps://example.com✅ 同源协议、域名、端口相同
https://example.comhttp://example.com❌ 跨域协议不同(HTTPS vs HTTP)
https://example.comhttps://api.example.com❌ 跨域子域名不同
https://example.com:80https://example.com:443❌ 跨域端口不同

2. 跨域的限制范围

跨域限制主要影响以下操作:

  • AJAX / Fetch 请求(XMLHttpRequest、axios、fetch API)
  • Web 字体(@font-face)
  • Canvas 绘制跨域图片
  • Web Storage / IndexedDB(部分浏览器限制)

但以下情况 不受跨域限制

  • <img><script><link><iframe> 等标签的 src 或 href 属性(但 JavaScript 无法直接读取返回内容)。
  • WebSocket(不受 SOP 限制,但可能受 CORS 影响)!!!!!!。

3. 为什么要有跨域限制?

  • 安全考虑:防止恶意网站窃取用户数据(如 Cookie、LocalStorage)。
  • 防止 CSRF(跨站请求伪造):避免攻击者诱导用户发送恶意请求。

4. 常见的跨域场景

  • 前端运行在 http://localhost:3000,但请求后端 API https://api.example.com
  • 主站 https://www.example.com 请求子域 https://api.example.com
  • 使用 CDN 资源时,不同域名导致跨域(如 https://cdn.example.com)。

前端解决跨域解决方案

1. CORS(跨域资源共享)最常用

  • 原理:服务器设置响应头(如 Access-Control-Allow-Origin)允许特定域访问资源。
  • 适用场景:前后端分离项目,后端可控。
  • 示例:
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Methods: GET, POST

2. JSONP(JSON with Padding)

  • 原理:利用 <script> 标签不受同源策略限制的特性,通过动态创建脚本获取数据。
  • 缺点:仅支持 GET 请求,安全性较低。
  • 示例
function handleResponse(data) {
  console.log(data);
}
const script = document.createElement('script');
script.src = 'https://api.example.com/data?callback=handleResponse';
document.body.appendChild(script);

3. 代理服务器(Proxy)

  • 原理:前端请求同域代理服务器,由代理服务器转发请求到目标服务器。
  • 实现方式
    • 开发环境:使用 webpack-dev-server、Vite 或 http-proxy-middleware。
// webpack.config.js
devServer: {
   // 代理所有以 /api 开头的请求
   '/api': {
     target: 'http://your-backend-server.com', // 目标服务器地址
     changeOrigin: true, // 改变请求头中的host为目标URL
     pathRewrite: {
       '^/api': '' // 重写路径,去掉/api前缀
     },
     secure: false, // 如果是https接口,需要配置这个参数
     // 其他可选配置
     // headers: {
     //   'X-Custom-Header': 'foobar'
     // }
   }
}

// vite.config.js
 server: {
     proxy: {
       // 字符串简写写法
       '/foo': 'http://localhost:4567',

       // 完整写法
       '/api': {
         target: 'http://jsonplaceholder.typicode.com',
         changeOrigin: true,
         ws: true, // 是否代理 WebSocket(默认为 true)
         rewrite: (path) => path.replace(/^/api/, ''),
         // 更多配置
         // configure: (proxy, options) => {
         //   // proxy 是 'http-proxy' 的实例
         // }
       },
       // 正则表达式写法
       '^/fallback/.*': {
         target: 'http://jsonplaceholder.typicode.com',
         changeOrigin: true,
         rewrite: (path) => path.replace(/^/fallback/, '')
       }
     }
   }

生产环境:通过 Nginx 反向代理。

location /api {
  proxy_pass https://api.example.com;
}

4. WebSocket

  • 原理:WebSocket 协议不受同源策略限制,适用于实时通信。
  • 示例
const socket = new WebSocket('wss://api.example.com');
socket.onmessage = (event) => {
  console.log(event.data);
};

5. postMessage

  • 原理:通过 window.postMessage 实现不同窗口(如 iframe、弹窗)间的跨域通信。
  • 示例
// 发送方
window.parent.postMessage('Hello', 'https://target.com');
// 接收方
window.addEventListener('message', (event) => {
  if (event.origin === 'https://source.com') {
    console.log(event.data);
  }
});

6. 修改 document.domain

  • 原理:将子域和父域的 document.domain 设置为相同值(仅适用于主域相同的情况)。
  • 示例
// a.example.com 和 b.example.com
document.domain = 'example.com';

7. 跨域资源共享的其他头部

  • 服务器可设置更多 CORS 头部以细化控制:
    • Access-Control-Allow-Headers: 允许的自定义头。
    • Access-Control-Allow-Credentials: 是否允许携带 Cookie。

8. 浏览器扩展或插件

  • 临时解决方案:如 Chrome 的跨域插件(Allow CORS),或启动浏览器时禁用安全策略(仅开发用):
chrome.exe --disable-web-security --user-data-dir=/tmp

9. 服务端转发(BFF模式)

  • 后端提供一个统一接口聚合第三方服务,前端只与同域后端交互。

注意事项:

  • 安全性:确保 CORS 或代理配置不会开放敏感资源。
  • 生产环境:优先使用 CORS 或代理,避免 JSONP 等不安全方案。

根据项目需求(如开发环境调试、生产部署、实时通信等)选择合适的方案。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值