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

大家好,我是有一点想法的thinkmars,目前在准备面试与工作,借着间隙时间学习复习,写一点基础文章,欢迎想找工作的人与我一起学习,一起讨饭吃~


前言

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

什么是跨域(Cross-Origin)?

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

1. 什么是"同源"?

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

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

2. 跨域的限制范围

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

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

但以下情况 不受跨域限制

  • <img><script><link><iframe> 等标签的 srchref 属性(但 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)允许特定域访问资源。

  • 适用场景:前后端分离项目,后端可控。

  • 示例

    http 复制代码
    Access-Control-Allow-Origin: https://example.com
    Access-Control-Allow-Methods: GET, POST

2. JSONP(JSON with Padding)

  • 原理 :利用 <script> 标签不受同源策略限制的特性,通过动态创建脚本获取数据。

  • 缺点:仅支持 GET 请求,安全性较低。

  • 示例

    javascript 复制代码
    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。

      javascript 复制代码
      // 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 反向代理。

      nginx 复制代码
      location /api {
        proxy_pass https://api.example.com;
      }

4. WebSocket

  • 原理:WebSocket 协议不受同源策略限制,适用于实时通信。

  • 示例

    javascript 复制代码
    const socket = new WebSocket('wss://api.example.com');
    socket.onmessage = (event) => {
      console.log(event.data);
    };

5. postMessage

  • 原理 :通过 window.postMessage 实现不同窗口(如 iframe、弹窗)间的跨域通信。

  • 示例

    javascript 复制代码
    // 发送方
    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 设置为相同值(仅适用于主域相同的情况)。

  • 示例

    javascript 复制代码
    // 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),或启动浏览器时禁用安全策略(仅开发用):

    bash 复制代码
    chrome.exe --disable-web-security --user-data-dir=/tmp

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

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

注意事项:

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

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

相关推荐
极客小俊25 分钟前
粘性定位Position:sticky属性是不是真的没用?
前端
云端看世界27 分钟前
ECMAScript 类型转换 下
前端·javascript
云端看世界30 分钟前
ECMAScript 运算符怪谈 下
前端·javascript
云端看世界31 分钟前
ECMAScript 函数对象实例化
前端·javascript
前端爆冲31 分钟前
基于vue和flex实现页面可配置组件顺序
前端·javascript·vue.js
云端看世界33 分钟前
ECMAScript 中的特异对象
前端·javascript
il35 分钟前
Deepdive into Tanstack Query - 2.1 QueryClient 基础
前端
_十六37 分钟前
看完就懂!用最简单的方式带你了解 TypeScript 编译器原理
前端·typescript
云端看世界39 分钟前
ECMAScript 运算符怪谈 上
前端·javascript·ecmascript 6
前端涂涂39 分钟前
express的介绍,简单使用
前端