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

公众号:小博的前端笔记

一、主流解决方案详解

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.comb.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.comapp2.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 等更安全的方案。"

相关推荐
Java技术小馆4 分钟前
GitDiagram如何让你的GitHub项目可视化
java·后端·面试
UGOTNOSHOT13 分钟前
7.4项目一问题准备
面试
贵沫末16 分钟前
React——基础
前端·react.js·前端框架
aklry28 分钟前
uniapp三步完成一维码的生成
前端·vue.js
Rubin9335 分钟前
判断元素在可视区域?用于滚动加载,数据埋点等
前端
爱学习的茄子35 分钟前
AI驱动的单词学习应用:从图片识别到语音合成的完整实现
前端·深度学习·react.js
用户38022585982436 分钟前
使用three.js实现3D地球
前端·three.js
程序无bug38 分钟前
Spring 面向切面编程AOP 详细讲解
java·前端
zhanshuo38 分钟前
鸿蒙UI开发全解:JS与Java双引擎实战指南
前端·javascript·harmonyos
撰卢1 小时前
如何提高网站加载速度速度
前端·javascript·css·html