1. 題目與適用場景
電商 Web Push 通知需要把使用者帶到訂單詳情。通知可能在應用程式未開啟、已有應用程式視窗或使用者點擊某個 action 時觸發。請使用 navigate 選項設計深連結,並說明 URL 解析、權限、點擊回退、重複開啟和 Service Worker 生命週期。
2. 面試官考察點
- 是否知道
NotificationOptions.navigate是導航 URL,Notification.navigate只讀回傳解析後的絕對 URL 或空字串。 - 是否能區分通知主體導航、action 導航和
notificationclick事件回退。 - 是否處理權限、HTTPS、同源策略、開放重新導向、重複通知和已有視窗重用。
- 是否能把業務路由恢復、驗證與冪等放在應用層,而非依賴瀏覽器自動導航完成。
3. 回答前需要釐清的問題
- 通知由頁面腳本還是 Service Worker 的
showNotification建立? - 深連結是否允許外部 URL,訂單詳情需要登入後如何恢復?
- 使用者點擊通知主體與 action 時,是否要進入不同頁面或執行不同動作?
- 已有同源視窗時,產品希望聚焦並重用,還是建立新視窗?
4. 30 秒回答框架
我會在 HTTPS 下由 Service Worker 建立帶 navigate 的持久通知,並只寫入經 allowlist 驗證的同源 URL。點擊主體或 action 時,瀏覽器可導航到對應 URL;若 action 沒有自己的 navigate,在 notificationclick 中處理業務回退,先聚焦已有視窗,再由客戶端路由恢復訂單。權限被拒絕、URL 無效或驗證失敗都要有明確的應用層兜底。
5. 分步驟深入解答
第一步:建立經驗證的通知 URL
const target = new URL(`/orders/${orderId}`, self.location.origin);
await self.registration.showNotification("訂單已出貨", {
body: "點擊查看物流進度",
tag: `order-${orderId}`,
navigate: target.href,
data: { orderId },
});navigate 會依通知建立時的 base URL 解析。服務端下發的路徑必須經同源與路由 allowlist 驗證,不能把任意使用者輸入直接當作跳轉地址。
第二步:區分主體與 action 導航
await self.registration.showNotification("訂單待確認", {
body: "請選擇操作",
navigate: "/orders/123",
actions: [
{ action: "open", title: "查看訂單", navigate: "/orders/123" },
{ action: "help", title: "聯絡客服" },
],
});點擊 action 時,action 自己的 navigate 優先;沒有該 URL 時才進入 notificationclick 事件邏輯。主體導航與 action 導航都要使用同一套 allowlist 與驗證恢復規則。
第三步:處理點擊回退與已有視窗
self.addEventListener("notificationclick", (event) => {
event.notification.close();
if (event.action === "help") {
event.waitUntil(clients.openWindow("/support"));
return;
}
event.waitUntil(clients.matchAll({ type: "window", includeUncontrolled: true })
.then((windows) => windows[0]?.focus() ?? clients.openWindow("/orders/123")));
});實際應用應檢查視窗 URL、等待 Service Worker 控制並傳遞可信的 data,不要固定寫死訂單號。瀏覽器實作可以重用或新建頂層視窗,產品邏輯應允許兩種結果。
第四步:權限、協定與安全邊界
通知需要使用者授予權限,持久通知還需要 Service Worker;相關 API 依賴安全上下文。權限不是業務授權,訂單 API 仍必須在開啟頁面後重新驗證。只允許同源或明確的受信任外部來源,避免開放重新導向和釣魚式深連結。
第五步:恢復應用程式狀態與冪等
頁面開啟後讀取路徑和 data.orderId,先顯示載入狀態,再請求訂單並驗證使用者身份。重複點擊同一 tag 的通知應合併或更新;客戶端路由切換、焦點恢復和埋點都要冪等,避免一次點擊建立多個請求或重複扣減狀態。
6. 高品質示範回答
我會讓 Service Worker 只產生 allowlist 內的同源navigateURL,並給通知設定穩定tag。主體點擊依瀏覽器導航,action 若有自己的 URL 則優先使用;沒有 URL 的 action 由notificationclick聚焦已有視窗或開啟回退頁。頁面開啟後重新驗證、讀取訂單參數並冪等恢復狀態。權限、HTTPS、開放重新導向和外部 URL 都單獨驗證,不能把通知導航當作業務授權。
7. 常見錯誤
- 把使用者輸入直接放入
navigate→ 開放重新導向 → 只允許同源和路由 allowlist。 - 認為所有點擊都會觸發自訂 click 處理 → 主體可能由瀏覽器直接導航 → 僅對沒有 action URL 的分支依賴
notificationclick。 - 把權限當成訂單授權 → 越權查看資料 → 頁面開啟後重新驗證。
- 每次點擊都
openWindow→ 重複視窗和重複請求 → 先匹配同源視窗並讓恢復邏輯冪等。 - 忽略 Service Worker 生命週期 → 非同步操作被中斷 → 用
event.waitUntil管理完成的 Promise。
8. 追問及應對
追問一:Notification.navigate 回傳什麼?
它是只讀字串屬性,回傳通知導航 URL 的絕對序列化值;沒有設定有效 URL 時回傳空字串。
追問二:action 沒有 navigate 會怎樣?
該 action 不會自動導航,點擊可進入 notificationclick 事件,由 Service Worker 執行自訂邏輯。
追問三:為什麼仍要在頁面重新驗證?
通知 URL 和 data 只是導航提示,不代表使用者身份或資源權限。訂單 API 必須依目前工作階段和服務端授權重新檢查。
追問四:如何測試跨視窗行為?
覆蓋無視窗、已有同源視窗、視窗未受 Service Worker 控制、主體點擊、action 點擊、權限拒絕和無效 URL,並斷言最終只產生一次應用程式恢復請求。