1. 題目與適用場景
訂單狀態通知提供「查看訂單」「確認收貨」「聯絡客服」三個 action。使用者可能在應用程式關閉、已有視窗或登入過期時點擊。請用 Notification action 的 navigate 設計流程,並說明瀏覽器自動導航與 notificationclick 自訂處理如何協作。
2. 面試官考察點
- 是否理解通知主體的
navigate與 action 的navigate是獨立 URL,action URL 優先於事件回呼。 - 是否知道沒有 action URL 時才由
notificationclick處理,並能正確使用event.waitUntil。 - 是否能驗證同源 URL、權限、登入狀態與 Service Worker 生命週期。
- 是否能用 tag、業務冪等鍵和客戶端恢復避免重複執行確認或開啟多個視窗。
3. 回答前需要釐清的問題
- 「確認收貨」是否允許 GET 導航,還是必須經過 POST API 和二次確認?
- 未登入時是先開啟登入頁,還是把目標 action 暫存到登入後恢復?
- action 的目標是否允許外部客服網域?
- 已有視窗時應聚焦、傳送訊息,還是建立獨立視窗?
4. 30 秒回答框架
我會把只有讀取的查看 action 映射到同源詳情 URL,把有副作用的確認 action 留給 notificationclick,在 Service Worker 中呼叫帶冪等鍵的 API,再導航到結果頁。每個 URL 經 allowlist 與權限驗證;事件非同步邏輯由 waitUntil 管理。已有視窗先聚焦並傳送可信訊息,失敗時再開啟回退頁。
5. 分步驟深入解答
第一步:宣告主體與 action URL
await self.registration.showNotification("訂單 #123", {
body: "請選擇操作",
tag: "order-123",
navigate: "/orders/123",
data: { orderId: "123", version: 4 },
actions: [
{ action: "view", title: "查看訂單", navigate: "/orders/123" },
{ action: "confirm", title: "確認收貨" },
{ action: "help", title: "聯絡客服", navigate: "/support/orders/123" },
],
});主體和 action 都應使用經驗證的同源 URL。tag 用於合併或更新同一訂單通知,data 只攜帶恢復所需的非敏感識別碼。
第二步:區分無副作用與有副作用 action
view 和 help 只有導航,瀏覽器可直接處理。confirm 沒有 navigate,因此進入 notificationclick;它必須呼叫服務端冪等 API,而不是把確認動作編碼進 URL 查詢參數。
第三步:實作 notificationclick 回退
self.addEventListener("notificationclick", (event) => {
event.notification.close();
const { orderId, version } = event.notification.data ?? {};
if (event.action !== "confirm" || !orderId) return;
event.waitUntil(confirmDelivery(orderId, version).then(() =>
focusOrOpen(`/orders/${encodeURIComponent(orderId)}?confirmed=1`)));
});生產程式還要捕捉網路失敗、過期版本和未授權回應,並把錯誤交給結果頁顯示。waitUntil 讓 Service Worker 在 Promise 完成前保持事件存活。
第四步:處理視窗和登入恢復
focusOrOpen 應先匹配同源且受控的視窗,再透過 postMessage 傳遞經驗證的路徑;沒有可用視窗才呼叫 clients.openWindow。登入過期時只傳遞短期目標狀態,登入完成後由頁面重新讀取訂單並授權。
第五步:安全、權限與冪等
通知權限只決定能否展示通知,不代表訂單授權。URL 必須限制協定、來源與路徑;確認 API 使用訂單號、版本或冪等鍵防止重複點擊。取消通知、重複 tag 和多裝置同時點擊都應有明確的服務端狀態機。
6. 高品質示範回答
我會把查看和協助定義為同源navigate,把確認收貨留給notificationclick,因為它有副作用。Service Worker 用waitUntil呼叫帶訂單版本和冪等鍵的確認 API,成功後聚焦已有視窗或開啟結果頁。所有 URL 做 allowlist 驗證,權限不等於業務授權,登入恢復必須重新驗證。測試覆蓋主體點擊、各 action、重複點擊、離線、過期版本和多視窗。
7. 常見錯誤
- 用 GET URL 觸發確認收貨 → 預取或重複點擊造成副作用 → 只在事件中呼叫冪等 POST API。
- 以為 action 沒有 URL 會自動開啟主體 URL → 行為不明確 → 在
notificationclick中明確處理。 - 把完整訂單資料放入
data→ 暴露敏感資訊 → 僅傳短識別碼,頁面重新請求授權資料。 - 非同步操作不使用
waitUntil→ Worker 提前終止 → 管理所有關鍵 Promise。 - 每次都建立新視窗 → 狀態分裂 → 優先匹配並聚焦同源視窗。
8. 追問及應對
追問一:action.navigate 和 notificationclick 誰優先?
有 action 自己的 navigate 時,瀏覽器可依該 URL 導航;沒有 URL 的 action 才需要 notificationclick 自訂處理。
追問二:為什麼確認收貨不能只放進 URL?
導航可能被預取、重播或重複點擊,無法表達可靠的副作用語意。確認必須由服務端冪等 API 和授權狀態機完成。
追問三:如何處理登入過期?
開啟登入頁時保存短期、不可竄改的目標狀態;登入成功後由頁面重新請求訂單並檢查權限,再恢復結果頁。
追問四:如何驗證不會重複執行?
用同一訂單版本和冪等鍵連續觸發主體、action、多視窗和多裝置點擊,斷言服務端只產生一次確認狀態轉換。