iframe跨域的幾種經常使用方法

  • 蘇格團隊
  • 做者:Brady

背景

隨着業務的發展,天然地會有一些公共的業務被抽離成爲公共組件共各個項目使用。可是因爲各個項目用到的技術棧都有所不一樣,因此這個公共組件就不能方便地被引用了。爲解決這個問題,咱們把這個組件寫成了單獨的頁面掛到一個域名下,其餘項目採用iframe或者webview的方式去加載這個頁面,從而實現功能的簡單複用。
不過這過程當中也產生了不少問題,單是跨域就會出現好幾回了。如下我將會介紹我遇到的跨域問題以及一些解決方法。html

爲何會跨域

爲了保證用戶信息的安全,95年的時候Netscape公司引進了同源策略,裏面的同源指的是三個相同:協議、域名、端口。
違反了同源策略就會出現跨域問題,主要表現爲如下三方面:node

  • 沒法讀取cookie、localStorage、indexDB
  • DOM沒法得到
  • ajax請求沒法發送

場景

最近在作一個需求,須要用iframe引入一個別人封裝好的相似視頻播放器的東西。iframe裏面有一個全屏的按鈕,點擊後須要頁面讓iframe全屏,因爲受到同源策略的限制,iframe沒法告訴頁面全屏。web

解決辦法

設置domain

document.domain做用是獲取/設置當前文檔的原始域部分,同源策略會判斷兩個文檔的原始域是否相同來判斷是否跨域。這意味着只要把這個值設置成同樣就能夠解決跨域問題了。
在此我將domain設置爲一級域名的值,a頁面url爲a.demo.com,a頁面中iframe引用的b頁面url爲b.demo.com,具體設置爲ajax

document.domain = 'demo.com'
複製代碼

設置完以後,在a頁面的window上掛載使iframe全屏的方法跨域

// a頁面
window.toggleFullScreen = () => {
    // do something
}
複製代碼

在b頁面上能夠直接獲取到a頁面的window對象並直接調用安全

// b頁面
window.parent.toggleFullScreen()
複製代碼

可是這個值的設置也有必定限制,只能設置爲當前文檔的上一級域或者是跟該文檔的URL的domain一致的值。如url爲a.demo.com,那domain就只能設置爲demo.com或者a.demo.com。所以,設置domain的方法只能用於解決主域相同而子域不一樣的狀況。bash

使用中間頁面

咱們還可使用一個與a頁面同域名但不一樣路由的c頁面做爲中間頁面,b頁面加載c頁面,c頁面調用a頁面的方法,從而實現b頁面調用a頁面的方法。具體操做以下:
在a頁面的node層新開一個路由,此路由加載一個c頁面做爲中間頁面,c頁面的url爲a.demo.com/c。c頁面只是一個簡單的html頁面,在window的onload事件上調用了a頁面的方法。cookie

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    <script>
        window.onload = function () {
            parent.parent.toggleFullScreen();
        }
    </script>
</body>
</html>
複製代碼

因爲c頁面和a頁面是符合同源策略的,因此能夠避開跨域問題,執行全屏的方法。dom

postmessage

window.postMessage方法能夠安全地實現跨源通訊,寫明目標窗口的協議、主機地址或端口就能夠發信息給它。post

// b頁面
parent.postMessage(
    value,
    "http://a.demo.com"
);
複製代碼
// a頁面
window.addEventListener("message", function( event ) {
    if (event.origin !== 'http://b.demo.com') return;
    toggleFullScreen()
 });
複製代碼

爲了安全,收到信息後要檢測下event.origin判斷是否要收信息的窗口發過來的。

總結

經過以上的方法,咱們就能夠和iframe自由通訊啦。

相關文章
相關標籤/搜索