跳到主要內容
前端開發

Google App 內建瀏覽器:about:blank 佔位頁被關閉的排查紀錄

記錄 iOS Google App 內建瀏覽器在非同步開啟外部頁面時,about:blank 佔位分頁被自動關閉,導致第三方登入或外部導轉失敗的排查與解法。

W

這次遇到的問題,是在 iOS 的 Google App 內建瀏覽器中,第三方登入或外部導轉偶爾會完全沒有反應,最後只能等到流程逾時。

最後查到的原因不是 API,也不是 Google 登入本身,而是:

原本預先開好的 about:blank 分頁,在等待伺服器回覆期間,被 Google App 自己關掉了。

為什麼需要先開一個空白分頁?

第三方登入或付款流程通常不是點下按鈕後,就立刻知道要前往哪個網址。

實際流程比較像:

使用者點擊按鈕
↓
向 Server 取得導轉網址
↓
等待回應
↓
開啟外部網站

但瀏覽器對 window.open() 有 Popup Blocker 限制。

如果等非同步請求完成後才呼叫:

const url = await getRedirectUrl();

window.open(url, "_blank");

新視窗可能已經失去使用者操作帶來的開窗權限,而被瀏覽器阻擋。

因此原本採用的是「先卡位、後導轉」:

const win = window.open("about:blank", "_blank");

const url = await getRedirectUrl();

win.location.href = url;

流程變成:

使用者點擊
↓
先開 about:blank
↓
等待 Server
↓
取得網址
↓
把剛才的分頁導向真正網址

這個做法在一般 Safari、Chrome 上原本都能正常使用。

Google App 的問題:about:blank 自己消失了

問題出現在 Google App 的 iOS 內建瀏覽器。

實測發現:

window.open("about:blank")
↓
剛開啟時 window.closed = false
↓
等待約 1 秒
↓
window.closed = true

也就是:

分頁確實成功開啟了,但還沒等 Server 回傳網址,就被容器關掉了。

後續即使再執行:

win.location.href = redirectUrl;

也已經沒有作用,因為 win 指向的視窗早就被關閉。

換成真正的佔位頁後就正常

為了確認問題是不是「跨網域導轉」造成的,當時做了幾組對照測試:

測試方式結果
直接開啟真正網址✅ 正常
about:blank → 延遲後導轉❌ 失敗
同源佔位頁 → 延遲後導轉✅ 正常
同源佔位頁 → Google✅ 正常
同源佔位頁 → 其他外部網站✅ 正常

最關鍵的差異就是:

about:blank
→ 會被關閉

而:

/redirecting.html
→ 分頁持續存在
→ 可以正常導向下一個網址

因此最後沒有再使用純空白頁,而是改成一個非常簡單的同源佔位頁:

<h1>處理中</h1>
<p>請稍候...</p>

不需要複雜 JavaScript,只要它是一個真正載入完成的頁面即可。

只針對 Google App 分流

因為 Safari、Chrome 原本的流程沒有問題,所以最後沒有全面修改。

而是透過 User-Agent 中的 GSA/ 特徵辨識這次遇到的 Google App 環境:

function isGoogleApp() {
  return /\bGSA\//.test(navigator.userAgent);
}

再決定預開哪一種頁面:

const placeholderUrl = isGoogleApp()
  ? "/redirecting.html"
  : "about:blank";

const win = window.open(placeholderUrl, "_blank");

概念就是:

Google App
└─ 開真正的同源佔位頁

Safari / Chrome
└─ 維持原本 about:blank

這樣可以把修改範圍控制在實際發生問題的環境,不影響原本正常的瀏覽器。

這次踩坑後的心得

這次最容易誤判的地方,是:

window.open() 有成功

不代表:

這個 Window 一段時間後還活著

如果流程是:

先開視窗
↓
等待非同步結果
↓
再修改 location

除了要檢查:

win !== null

其實還可以注意:

win.closed

尤其是在 App 內建瀏覽器或 WebView 環境中,行為不一定和 Safari、Chrome 完全相同。

最後我的處理原則變得很簡單:

如果必須預開分頁等待非同步結果,不要假設 about:blank 在所有瀏覽器容器裡都會一直存在;必要時使用真正的同源佔位頁。

分享這篇