郝云逸 發表於 2025-10-28 10:52:00

Web前端入门第 89 问:总结 8 种跨域通信处理方案

<p>为什么会跨域?跨域是谁附加的限制?为什么 APP 不会有跨域问题?</p>
<p>首先跨域问题是由于浏览器的同源策略(Same-Origin Policy)导致的,基本上所有浏览器都有限制,默认情况是不允许跨域访问的!!</p>
<p>APP 的请求不受浏览器的同源策略限制,所以不存在跨域。类似一个服务器像另一个服务器发起请求一样,也不会受跨域影响。</p>
<p>想想一下:如果浏览器没有同源策略限制,A 网站可以随意访问 B 网站内容,那么现在 BAT 这些一线大厂还有护城河吗?所有网站的数据都无隐私可言了,各种钓鱼网站在浏览器中横飞!!那世道...简直太美~~</p>
<h2 id="什么是同源">什么是同源</h2>
<p><strong>同源:</strong>指的是协议、域名和端口都相同。任意一个不同,都会触发浏览器的同源策略,从而导致跨域。</p>
<p>以 MDM 的一个文档地址为例,看看 URL 不同的组成部分:https://developer.mozilla.org:443/zh-CN/docs/Web/JavaScript?a=b#hash</p>
<p><img src="https://img2024.cnblogs.com/blog/596097/202510/596097-20251028105140122-37555280.jpg"></p>
<h2 id="跨域解决方案">跨域解决方案</h2>
<p>虽然默认情况下浏览器是不允许跨域访问的,但通过一些配置手段,还是能够实现资源共享~~</p>
<h3 id="1跨域资源共享-cors">1、跨域资源共享 CORS</h3>
<p>目前主流的跨域共享方案,由服务器配置响应头告诉浏览器是否允许跨域访问:</p>
<pre><code class="language-http">// 或 * 表示所有源都可以访问
Access-Control-Allow-Origin: https://domain.com
// 允许的方法
Access-Control-Allow-Methods: GET, POST, OPTIONS
// 允许的自定义头
Access-Control-Allow-Headers: Content-Type, Authorization
// 允许携带 Cookie
Access-Control-Allow-Credentials: true
</code></pre>
<h3 id="2反向代理">2、反向代理</h3>
<p>原理就是前端请求同源服务器,由同源服务器向跨域目标发起请求,再由同源服务器返回结果给前端。绕过了浏览器同源策略,但需要服务器支持,如果请求量太大,对自己的服务器要求很高。</p>
<p>比如 nginx / node 中间件 / 开发环境的 dev-server 都是这种方式,以 nginx 跨域配置为例:</p>
<pre><code class="language-nginx">location /api/ {
proxy_pass https://domain.com/;# 需要请求的跨域目标
proxy_set_header Host $host;
}
</code></pre>
<h3 id="3websocket">3、WebSocket</h3>
<p>WebSocket 是 HTML5 新增的协议,允许浏览器和服务器之间进行全双工通信,天然支持跨域访问。由于是双向通信,所以对服务器压力也不小。</p>
<pre><code class="language-js">const ws = new WebSocket('wss://domain.com');
ws.onmessage = (event) =&gt; console.log(event.data);
</code></pre>
<h3 id="4jsonp">4、JSONP</h3>
<p>利用 <code>&lt;script&gt;</code> 标签,向目标服务器发起请求,目标服务器需要返回一段函数调用,将数据返回给前端。缺点是仅支持 get 请求,还容易引发 XSS 攻击!</p>
<pre><code class="language-js">function handleResponse(data) {
console.log(data);
}

const script = document.createElement('script');
script.src = 'https://domain.com/data?callback=handleResponse';
document.head.appendChild(script);
</code></pre>
<p><code>https://domain.com/data?callback=handleResponse</code> 需要返回 JS 代码调用函数执行:</p>
<pre><code class="language-js">handleResponse({ data: 'hello' });
</code></pre>
<h3 id="5postmessage">5、postMessage</h3>
<p>此方式一般多用于 iframe 的跨域通信,比如 A 网页使用 iframe 嵌入 B 网页,这种情况就可以使用 postMessage 通信:</p>
<p>发送者:</p>
<pre><code class="language-js">// 发送方
iframe.contentWindow.postMessage('data', 'https://target-domain.com');
</code></pre>
<p>接收者:</p>
<pre><code class="language-js">// 接收方
window.addEventListener('message', (event) =&gt; {
if (event.origin !== 'https://source-domain.com') {
    return;
}
console.log(event.data);
});
</code></pre>
<h2 id="不推荐的方案">不推荐的方案</h2>
<p>浏览器的版本升级后,一些老旧的跨域方案被弃用,比如:</p>
<h3 id="6documentdomain--iframe">6、document.domain + iframe</h3>
<p>在过去,如果同一个主域名,子域名不同的情况,比如:a.domain.com 和 b.domain.com 之间进行通信,可以通过设置 <code>document.domain = 'domain.com'</code> 来解决,但现在的浏览器已经限制使用了!!</p>
<h3 id="7windowname--iframe">7、window.name + iframe</h3>
<p>此方案有一些复杂,需要一个空白的同源页面用于绕过浏览器的同源策略,然后获取 iframe 的 name 属性值,此处有大小限制,最多 2MB 的数据。</p>
<p>流程:</p>
<pre><code class="language-text">源页面A (domainA.com)
   ↓ 创建iframe指向代理页面B (domainB.com)
代理页面B (domainB.com)
   ↓ 接收数据并存入 window.name
   ↓ 跳转至与A同源的空白页面C (domainA.com)
源页面A
   ↓ 访问iframe的window.name获取数据
</code></pre>
<p>流程图:</p>
<p><img src="https://img2024.cnblogs.com/blog/596097/202510/596097-20251028105147744-1045919346.jpg"></p>
<p>目前项目开发基本上已经不在使用这种方式,毕竟绕来绕去的,还不如一个 postMessage 跨域方案简单。</p>
<h3 id="8locationhash--iframe">8、location.hash + iframe</h3>
<p>通过修改 URL Hash 实现父子 iframe 间单向数据传输,虽然勉强也能算作一种跨域方案,但由于 URL 的长度限制,数据量也不能太大,实际使用中也不简单,所以项目上也很难见到它的身影~~</p>
<p>流程图:</p>
<p><img src="https://img2024.cnblogs.com/blog/596097/202510/596097-20251028105152357-1446124821.jpg"></p>
<h2 id="写在最后">写在最后</h2>
<p>除了文章中这 8 种跨域方案外,还有一些单向数据通信的方法,比如说:</p>
<p>1、使用 Fetch API 的 no-cors 模式。<br>
2、利用图片的 src 属性发起 GET 请求。<br>
3、使用 sendBeacon 发送分析数据。</p>
<p>这些方法都只能向服务器发送数据,没办法获得服务器的响应,所以一般多用于一些数据统计,比如:百度统计、谷歌分析等等。</p>
<p>当然也有一些<em>歪门邪道</em>,比如说:修改浏览器的配置允许跨域,编写浏览器插件支持跨域等等。</p>


</div>
<div id="MySignature" role="contentinfo">
    <p>&nbsp;</p>
<p style="font-size: 18px;font-weight: bold;">文章首发于微信公众号【<span style="color:rgb(255, 71, 87)">前端路引</span>】,欢迎 <span style="color:#4ec259">微信扫一扫</span> 查看更多文章。</p>
<p>
<img style="max-width: 320px;" src="https://images.cnblogs.com/cnblogs_com/linx/2447020/o_250228035031_%E5%85%AC%E4%BC%97%E5%8F%B7%E4%BA%8C%E7%BB%B4%E7%A0%81.png"/>
</p>
<p>本文来自博客园,作者:前端路引,转载请注明原文链接:https://www.cnblogs.com/linx/p/19171207</p>
<p>&nbsp;</p><br><br>
来源:https://www.cnblogs.com/linx/p/19171207
頁: [1]
查看完整版本: Web前端入门第 89 问:总结 8 种跨域通信处理方案