12/19/2017

Iframe 跨域傳值在 iOS 失效的解法﹍利用網址 + localStorage + cookie 並用

Iframe 跨域傳值在 iOS 失效的解法﹍利用網址 + localStorage + cookie 並用

A+
上一篇「利用隱藏的 Iframe 跨域傳送訊息實作」,很可惜在前端開發人員的大魔王(iOS)面前又失效了,在 iPhone 鬼打牆了很久才瞭解:

  • iOS 禁止 localStorage 跨域傳值
  • iOS 的 Safari 設定中,預設關閉 cookie
  • iOS 的 Chrome 跟一般 Chrome 不太一樣,封鎖了跨域的 localStorage 儲存

除非前端開發人員敢在網頁顯示提示訊息,例如建議「不要使用 iPhone、iPad」、或是「不要使用 Safari」、或是「iPhone 下不要用 Chorme」,否則遲早要面對、解決以上這些狀況。

以下紀錄如何處理這些難題的過程、以及範例程式碼。

(圖片出處: pixabay.com)


一、利用網址傳值


1. Safari 的預設選項

測試 iPhone 裝置的除錯工具,可參考這篇「利用 Chrome 對 iOS 裝置進行除錯(iPhone、iPad)的絕佳方案」。

根據這個討論串「Iframe localStorage on Safari and Safari mobile」,Safari 瀏覽器的設定中,雖然有「允許使用 cookie、允許跨域」的選項,但預設值竟然是關閉的,所以開發人員很可能測試半天也找不出無法跨域的原因。

但就算我們開啟了 Safari 跨域的選項,不代表其他使用者知道要去開啟這個選項,那麼我們做的網頁依然無法使用。


2. 利用網址傳值

還好有看到這篇「localstorage的跨域存储方案」提出了很棒的構想:

  • 利用網址參數傳值

把要傳送的數值放在 Iframe 裡面的網址,當成參數傳遞,就可以完美地繞過 localStorage 與 cookie 的限制!



二、iOS 的 Chrome 跨域問題


利用前述的「網址傳值」技巧,在 iOS 的 Safari,可以成功把跨 Iframe 傳的值,儲存在 localStorage 使用,不過接下來的關卡是 "iOS 的 Chrome"。

很神奇的,Safari 可以把傳過來的值儲存在 localStorage,但 Chrome 竟然無法儲存在 localStorage。說白話一點,iOS 下的 Chrome:

  • 可以儲存任何 localStorage
  • 唯獨 Iframe 跨域網址傳過來的資料,無法存在 localStorage

這個現象實在不知如何解釋,但又不能叫 iOS 使用者不准用 Chrome。

幸好還是發現了解決方法,Safari 預設會封鎖 cookie,但 Chrome 是不會封鎖 cookie 的。所以完美的解法就是,Iframe 用網址跨域傳遞的值:

  • Safari 存在 localStorage
  • Chrome 存在 cookie



三、範例程式碼


以下提供範例:

1. 母視窗

<!--載入 query-->
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>

<!--跨域 IFRAME-->
<iframe id="WFU_frame" src=""></iframe>

<script>
(function($) {
// 網址先編碼
var token = encodeURIComponent("第一筆資料"), // 填入跨域資料
userId = encodeURIComponent("第二筆資料"), // 填入跨域資料
href = "http://demo.wfublog.com/p/cross-domain-postmessage-iframe.html", // 填入跨域網址
search = "token=" + token + "&userId=" + userId, // 網址傳值參數
iframeSrc = href + "?" + search; // 完整 iframe 網址

// iframe 網址傳值
$("#WFU_frame").attr("src", iframeSrc);
})(jQuery);
</script>

修改說明請參照註解文字。


2. Iframe 頁面

<!--載入 jquery cookie-->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-cookie/1.4.1/jquery.cookie.min.js"></script>

<script>
// 分解網址參數 字串先解碼
var searchSet = decodeURIComponent(window.location.search).substring(1).split("&"),
i, token, userId;

// 從網址找出跨域傳值
for (i in searchSet) {
if (searchSet[i].indexOf("token") === 0) {
token = searchSet[i].split("=")[1];
}
if (searchSet[i].indexOf("userId") === 0) {
userId = searchSet[i].split("=")[1];
}
}

// 跨域傳值寫入 localStorage, for Safari
localStorage.token = token;
localStorage.userId = userId;

// 跨域傳值寫入 cookie, for Chrome
$.cookie("token", token, {
expires: 365,
path: "/"
});
$.cookie("userId", userId, {
expires: 365,
path: "/"
});
</script>

修改說明請參照註解文字。


更多 Javascript 相關技巧:
如這篇文章對你有幫助,歡迎「分享」或給我個讚:

沒有留言:

張貼留言注意事項:

◎ 勾選「通知我」可收到後續回覆的mail!
◎ 請在相關文章留言,與文章無關的主題請至「Blogger 中文論壇」。
◎ 提問若無法提供足夠的資訊供判斷,可能會被無視。建議先參考這篇「Blogger 提問技巧及注意事項」。
◎ CSS 相關問題非免費諮詢,建議使用「Chrome 開發人員工具」尋找答案。
◎ 手機版相關問題請參考「Blogger 行動版範本的特質」→「三、行動版範本不一定能執行網頁版工具」。
◎ 非官方範本問題、或貴站為商業網站 ,請參考「本站諮詢頁面」→「1. 諮詢服務」
◎ 若留言要輸入語法,"<"、">"這兩個符號請用其他符號代替,否則語法會消失!
◎ 為了過濾垃圾留言,所有留言不會即時發佈,請稍待片刻。
◎ 本站「已關閉自刪留言功能」。

TOP