解决跨域的几种种方法, 你都知道几种?

公众号:小博的前端笔记

一、主流解决方案详解

1. CORS (跨域资源共享)

  • 原理:服务器设置响应头告知浏览器允许跨域请求。

  • 关键响应头:

    yaml 复制代码
    Access-Control-Allow-Origin: *  // 或指定域名(如 https://example.com)
    Access-Control-Allow-Methods: GET, POST, PUT
    Access-Control-Allow-Headers: Content-Type, Authorization
    Access-Control-Allow-Credentials: true  // 允许发送Cookie
    Access-Control-Max-Age: 86400  // 预检请求缓存时间
  • 请求分类:

    • 简单请求 :直接发送(GET/POST/HEAD + 特定Header + application/x-www-form-urlencoded/multipart/form-data/text/plain)。
    • 预检请求 (Preflight) :非简单请求先发OPTIONS请求询问服务器(面试常考!)。
  • 代码示例:

    php 复制代码
    // 前端(需带凭证时)
    fetch('https://api.target.com/data', {
      credentials: 'include'
    });
    rust 复制代码
    // Node.js服务器设置
    res.setHeader('Access-Control-Allow-Origin', 'https://your-domain.com');
    res.setHeader('Access-Control-Allow-Credentials', 'true');

2. JSONP (JSON with Padding) (历史方案)

  • 原理 :利用<script>标签无跨域限制的特性。

  • 特点:

    • 仅支持GET请求
    • 需服务器配合返回函数调用(如 callbackName({data}))
  • 代码示例:

    xml 复制代码
    <script>
      function handleResponse(data) {
        console.log(data);
      }
    </script>
    <script src="https://api.target.com/data?callback=handleResponse"></script>

3. WebSocket

  • 原理:WebSocket协议本身支持跨域(建立连接时通过HTTP协商升级协议)。

  • 代码示例:

    ini 复制代码
    const socket = new WebSocket('ws://target.com');
    socket.onmessage = (event) => {
      console.log(JSON.parse(event.data));
    };

4. 代理服务器 (Proxy)

  • 原理:让同源服务器代理转发请求(绕过浏览器限制)。

  • 实现方式:

    • 开发环境:Webpack DevServer / Vite Proxy

      javascript 复制代码
      // vite.config.js
      export default {
        server: {
          proxy: {
            '/api': {
              target: 'http://target-server.com',
              changeOrigin: true,
              rewrite: path => path.replace(/^/api/, '')
            }
          }
        }
      }
    • 生产环境:Nginx反向代理

      bash 复制代码
      location /api/ {
        proxy_pass http://target-server.com/;
        proxy_set_header Host $host;
      }

5. postMessage

  • 适用场景:跨窗口通信(如iframe与父页面)。

  • 代码示例:

    csharp 复制代码
    // 发送方
    iframe.contentWindow.postMessage('data', 'https://target.com');
    ​
    // 接收方
    window.addEventListener('message', event => {
      if (event.origin !== 'https://sender.com') return;
      console.log(event.data);
    });

6. 修改 document.domain (仅限子域)

  • 限制 :仅适用于主域相同、子域不同的场景(如 a.example.com ↔ b.example.com)。

  • 代码:

    ini 复制代码
    // 两个页面都设置
    document.domain = 'example.com';

二、回答技巧

  1. 核心必答:CORS机制(尤其预检请求)、代理服务器原理。

  2. 对比方案:

    • CORS vs JSONP:安全性、请求方法支持度、现代API兼容性。
    • 代理服务器适用场景:解决开发环境跨域、隐藏真实接口地址。
  3. 安全提醒:

    • Access-Control-Allow-Origin: * 的风险
    • JSONP的XSS漏洞(需校验来源)
  4. 实际经验:提到Webpack/Vite代理配置或Nginx部署经验是加分项。


三、解决方案对比表

方案 适用场景 请求支持 安全性 复杂度
CORS 主流API交互 所有方法 ★★★(需配置) 中
JSONP 老旧浏览器兼容 GET ★ (易XSS) 低
代理服务器 开发环境/隐藏真实地址 所有方法 ★★★ 中
WebSocket 实时通信 双向通信 ★★★ 高
postMessage 跨窗口通信 数据传递 ★★ 中

💡 回答时强调"根据场景选方案":

  • 现代项目首选CORS
  • 本地开发用代理
  • 特殊场景考虑WebSocket/postMessage

四、document.domain 跨域解决方案详解

document.domain 是一种专门用于解决主域相同、子域不同的跨域问题的技术。下面我将详细讲解其原理、使用方法和注意事项。

原理机制

document.domain 的工作原理基于以下关键点:

  1. 同源策略限制:浏览器默认阻止不同源(协议+域名+端口)页面间的交互
  2. 域名继承关系 :子域(如 a.example.com)继承自主域(example.com)
  3. 属性设置 :通过将 document.domain 设置为相同的主域,浏览器会认为这些页面同源

使用场景

仅适用于以下情况:

  • 主域名相同(如 example.com)
  • 子域名不同(如 app1.example.com 和 app2.example.com)
  • 使用相同协议(都使用 HTTP 或 HTTPS)
  • 使用相同端口(如都使用 80 端口)

具体使用步骤

1. 在两个页面中都设置 document.domain

在需要相互通信的两个页面(如主页面和 iframe 页面)中,都需要设置 document.domain 为相同的主域:

xml 复制代码
<!-- 主页面:http://app1.example.com/index.html -->
<script>
// 设置为主域名
document.domain = 'example.com';
</script>
xml 复制代码
<!-- iframe 页面:http://app2.example.com/widget.html -->
<script>
// 同样设置为主域名
document.domain = 'example.com';
</script>
2. 通过 iframe 实现跨域通信
父页面访问 iframe 内容
xml 复制代码
<!-- 父页面:http://app1.example.com/index.html -->
<iframe id="childFrame" src="http://app2.example.com/widget.html"></iframe>

<script>
document.domain = 'example.com';

const iframe = document.getElementById('childFrame');

iframe.onload = function() {
  // 现在可以安全访问 iframe 内容
  const childWindow = iframe.contentWindow;
  
  // 调用 iframe 中的函数
  childWindow.childFunction();
  
  // 访问 iframe 中的变量
  console.log(childWindow.childVariable);
};
</script>
iframe 访问父页面内容
xml 复制代码
<!-- iframe 页面:http://app2.example.com/widget.html -->
<script>
document.domain = 'example.com';

// 访问父页面的全局变量
console.log(parent.parentVariable);

// 调用父页面的函数
parent.parentFunction();
</script>
3. 使用 window.open() 打开窗口的跨域通信
ini 复制代码
// 主页面:http://app1.example.com/index.html
document.domain = 'example.com';

const newWindow = window.open('http://app2.example.com/page.html');

// 等待新窗口加载完成
newWindow.onload = function() {
  // 访问新窗口的内容
  newWindow.childFunction();
};
xml 复制代码
<!-- 新窗口:http://app2.example.com/page.html -->
<script>
document.domain = 'example.com';

// 访问打开它的窗口
opener.parentFunction();
</script>
关键注意事项
  1. 设置限制:

    • 只能设置为当前域名的后缀(如 sub.example.com 只能设置为 example.com)
    • 不能设置为不相关的域名
    • 不能设置为公共后缀(如 .com, .org)
  2. 端口重置:

    • 设置 document.domain 后,端口号会被重置为 null
    • 两个页面必须都设置相同的 document.domain
  3. 现代浏览器限制:

    • Chrome 等现代浏览器要求设置的值必须是当前域名的有效父域
    • 如果使用了 HSTS(HTTP Strict Transport Security),可能无法修改 document.domain
  4. 安全性考虑:

    • 放宽了同源策略限制,需确保只与信任的页面通信
    • 避免设置过于宽泛的域(如顶级域名)

要点总结

"document.domain 是一种解决主域相同、子域不同的跨域方案。它通过将两个页面的 document.domain 设置为相同的主域,使浏览器将它们视为同源。使用步骤是:1) 在两个页面中都设置 document.domain = '主域名';2) 通过 iframe 或 window.open 进行通信。但需要注意它只能用于子域之间,现代浏览器有一些限制,并且设置后会重置端口号。在实际项目中,更推荐使用 CORS 或 postMessage 等更安全的方案。"

相关推荐
子兮曰4 天前
jev-ultrafast 深度解析:7 秒订机票的浏览器 Agent 是如何炼成的
前端·后端·agent
子兮曰4 天前
Jev 爆发一周:7 秒 Agent 背后的 System One 生态与三场争议
前端·后端·ai编程
前端小万4 天前
写公众号赚了 3000 块后,我做了一款叫 "一键成稿" 的软件
前端·微信小程序
爱勇宝4 天前
ZCode 开源 24 小时:一份没有历史的账本,回答不了"有没有偷代码"
前端·后端·chatglm (智谱)
三十而立洋4 天前
Cookie 详解:从产生到安全,一次讲透
前端·javascript
晨米酱4 天前
AGENTS.md:Agent 的上下文策略层
面试·架构·agent
卡布鲁4 天前
把一个 Vite + Vue3 应用塞进 qiankun (React + Umi3) 主站:十个坑的复盘
前端·javascript·react.js
彧azz4 天前
Linux 环境下 Redis 学习总结:数据类型、持久化、锁、事务、主从与缓存问题
linux·redis·笔记·学习·面试
汉堡大王95274 天前
Jev:不是聊天机器人, 而是一个智能 if 语句
前端·人工智能·后端
梦想很大很大4 天前
从运行事实到回归证据:Workrun 的 Telemetry 与 Evaluation 实践
前端·人工智能·后端