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

大家好,我是有一点想法的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 等不安全方案。

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

相关推荐
京东零售技术38 分钟前
在京东 探索技术的无限可能
面试
棉花糖超人1 小时前
【从0-1的HTML】第2篇:HTML标签
前端·html
exploration-earth1 小时前
本地优先的状态管理与工具选型策略
开发语言·前端·javascript
OpenTiny社区1 小时前
开源之夏报名倒计时3天!还有9个前端任务有余位,快来申请吧~
前端·github
ak啊1 小时前
WebGL魔法:从立方体到逼真阴影的奇妙之旅
前端·webgl
hang_bro1 小时前
使用js方法实现阻止按钮的默认点击事件&触发默认事件
前端·react.js·html
用户90738703648642 小时前
pnpm是如何解决幻影依赖的?
前端
寒山李白2 小时前
Java 依赖注入、控制反转与面向切面:面试深度解析
java·开发语言·面试·依赖注入·控制反转·面向切面
树上有只程序猿2 小时前
Claude 4提升码农生产力的5种高级方式
前端
傻球2 小时前
没想到干前端2年了还能用上高中物理运动学知识
前端·react.js·开源