iframe跨域通信實戰

"長時間不寫文章,開頭的方式總是那麼出奇的相似",最近很忙,好久沒寫博客了啊(是不是?)。
更換工作已經有三個月有餘,這段三個月把過去三年沒加過的班都加了一次。收穫挺多,發現的問題也挺多。
一直也在思考一些問題:
如何把自己遇見的問題好好的理解並且總結?
如何很好的學習新知識,不只是停留在用的基礎上?
……

上面的問題我一直在嘗試更適合我的方法,暫時就不扯淡了,先嚐試一下把這段時間過程中遇見的問題總結下,然後爭取給看文的你以我的方式描述清楚,我想我應該就把第一個問題解決了。

簡介

項目實戰中postMessage的使用

問題描述

前提:我們的項目與兄弟團隊的項目都是基於同一套基礎框架開發,只是在視圖層我們有各自的一套東西。
項目是一個hybrid項目,目前是以h5的形式在開發,後期可以輕鬆轉爲hybrid。目前已經以h5的形式上線到自家公衆號,大致是在硬件上產出一份報告,h5把報告的內容展示出來。
新需求是,把報告推給兄弟團隊的APP,在APP內也能打開我們的報告進行查看報告然後點評。
兄弟團隊爲了最小的改動實現這個功能,用了iframe的形式打開我們推過去的報告鏈接,問題就出在報告能在兄弟團隊的APP中打開卻不能跳轉鏈接,問題是因爲我們的基礎框架提供的forward方法在app內是通過native的方式來跳轉,但是我們的協議不會被兄弟團隊的app識別,簡單說就是跳轉直接被攔截了。
經過幾番商量,商定出三個解決方案:

  • iframe跨域通信
  • 他們重新做一套(不可取的備選)
  • 我們來實現他們的點評業務(業務交錯不可取)

雜貨鋪中的知識點

很明顯我們更傾向於第一種方式,彷彿記得之前總結過類似的一篇文章同源策略和跨域知識點學習,當時完全是參考知識點進行的一次搬移,現在看來完全還是沒有透徹理解。

  • 同源:同源即需要協議主機名(域名或者ip)端口相同。
  • 跨域:域名不一致了,自然是不同源的,這種情況下要通信何解呢?

postMessage派上用途。
h5模式下子頁面跳轉協議可以正常使用history模式或者非單頁模式跳轉。(知識點:這種情況下iframe的src不會隨iframe內跳轉鏈接的變化而變化,父頁面不能監聽到子頁面內的頁面變化)
hybrid模式下鏈接跳轉被攔截,頁面表現就是鏈接點不了,如何讓父元素知道我點了什麼鏈接,然後來切換頁面,他們做url更換,來實現跳轉並且支持切換頁面操作,如此我們就需要子頁面給父頁面發送一條message告訴它我要跳轉到哪一個頁面。

實戰知識點

頁面跳轉中我們使用了$forward方法進行收口,所有的跳轉都需要經過這個方法(對於收口的好處這裏就體現出來了),我只需要判斷ua在跳轉前執行以下消息發送的方法。

/**
 * 頁面跳轉方法
 * @param page 要跳轉的頁面名稱
 * @param param 跳轉時需要額外攜帶的參數
 */
$forward(page, param) {
    // _ extend getUrlParam getUrlRule loadPage isHybrid 省略
    var param = _.extend(_.getUrlParam(), param);
    let url = _.getUrlRule(page, param);
    if(isHybrid) {
        _.requestHybrid({
            // 省略
        });
    } else {
        _.loadPage(url);
    }
}

在跳轉前我們先檢測一下ua,判斷是否是在兄弟團隊app內做特殊處理

let ua = navigator.userAgent.toLowerCase(),
    isFriendHybrid = /friend_hybrid_\w+_(\d*\.?)+/.test(ua);
if(isFriendHybrid) {
    window.top.postMessage({
        tag: 'forward',
        url: url
    }, '*')
} else {
    this.$forward();
}

在兄弟團隊的父頁面只需要監聽message事件獲取我傳遞過去的消息做特殊處理即可

window.addEventListener('message', function(e) {
    console.log(e.data);
    // {tag: 'forward', url: ……}
})

例如在一個特殊位置我會在沒有pdf的時候直接彈出調試“暫時沒有報告”,用戶點擊之際顯示的是我彈出的toast,由於嵌入後有兼容問題,於是我們又約定了一個方法。

window.top.postMessage({
    tag: 'showtoast',
    content: '暫時沒有報告'
}, '*')

這應該就是一個典型的iframe跨域通信例子。

demo

https://jsfiddle.net/unofficial/xwaksbvn/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章