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

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

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

相关推荐
阿珊和她的猫3 小时前
v-scale-scree: 根据屏幕尺寸缩放内容
开发语言·前端·javascript
PAK向日葵5 小时前
【算法导论】PDD 0817笔试题题解
算法·面试
加班是不可能的,除非双倍日工资7 小时前
css预编译器实现星空背景图
前端·css·vue3
wyiyiyi7 小时前
【Web后端】Django、flask及其场景——以构建系统原型为例
前端·数据库·后端·python·django·flask
gnip8 小时前
vite和webpack打包结构控制
前端·javascript
excel8 小时前
在二维 Canvas 中模拟三角形绕 X、Y 轴旋转
前端
阿华的代码王国8 小时前
【Android】RecyclerView复用CheckBox的异常状态
android·xml·java·前端·后端
一条上岸小咸鱼8 小时前
Kotlin 基本数据类型(三):Booleans、Characters
android·前端·kotlin
Jimmy9 小时前
AI 代理是什么,其有助于我们实现更智能编程
前端·后端·ai编程
ZXT9 小时前
promise & async await总结
前端