上一篇「利用隱藏的 Iframe 跨域傳送訊息實作」,很可惜在前端開發人員的大魔王(iOS)面前又失效了,在 iPhone 鬼打牆了很久才瞭解:
除非前端開發人員敢在網頁顯示提示訊息,例如建議「不要使用 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 的 Safari,可以成功把跨 Iframe 傳的值,儲存在 localStorage 使用,不過接下來的關卡是 "iOS 的 Chrome"。
很神奇的,Safari 可以把傳過來的值儲存在 localStorage,但 Chrome 竟然無法儲存在 localStorage。說白話一點,iOS 下的 Chrome:
這個現象實在不知如何解釋,但又不能叫 iOS 使用者不准用 Chrome。
幸好還是發現了解決方法,Safari 預設會封鎖 cookie,但 Chrome 是不會封鎖 cookie 的。所以完美的解法就是,Iframe 用網址跨域傳遞的值:
以下提供範例:
1. 母視窗
修改說明請參照註解文字。
2. Iframe 頁面
修改說明請參照註解文字。
- 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 相關技巧: