具代表性的面試主題

前端面試題:通知 action 的 navigate 與 click 回退如何協作?

前端中等
Offer.cc 編輯團隊發佈 更新

題幹

請設計一個包含查看、確認與協助 action 的訂單通知,並說明每個 action 的導航優先級、回退處理和冪等驗證。

1. 題目與適用場景

訂單狀態通知提供「查看訂單」「確認收貨」「聯絡客服」三個 action。使用者可能在應用程式關閉、已有視窗或登入過期時點擊。請用 Notification action 的 navigate 設計流程,並說明瀏覽器自動導航與 notificationclick 自訂處理如何協作。

2. 面試官考察點

  • 是否理解通知主體的 navigate 與 action 的 navigate 是獨立 URL,action URL 優先於事件回呼。
  • 是否知道沒有 action URL 時才由 notificationclick 處理,並能正確使用 event.waitUntil
  • 是否能驗證同源 URL、權限、登入狀態與 Service Worker 生命週期。
  • 是否能用 tag、業務冪等鍵和客戶端恢復避免重複執行確認或開啟多個視窗。

3. 回答前需要釐清的問題

  1. 「確認收貨」是否允許 GET 導航,還是必須經過 POST API 和二次確認?
  2. 未登入時是先開啟登入頁,還是把目標 action 暫存到登入後恢復?
  3. action 的目標是否允許外部客服網域?
  4. 已有視窗時應聚焦、傳送訊息,還是建立獨立視窗?

4. 30 秒回答框架

我會把只有讀取的查看 action 映射到同源詳情 URL,把有副作用的確認 action 留給 notificationclick,在 Service Worker 中呼叫帶冪等鍵的 API,再導航到結果頁。每個 URL 經 allowlist 與權限驗證;事件非同步邏輯由 waitUntil 管理。已有視窗先聚焦並傳送可信訊息,失敗時再開啟回退頁。

5. 分步驟深入解答

第一步:宣告主體與 action URL

js
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

viewhelp 只有導航,瀏覽器可直接處理。confirm 沒有 navigate,因此進入 notificationclick;它必須呼叫服務端冪等 API,而不是把確認動作編碼進 URL 查詢參數。

第三步:實作 notificationclick 回退

js
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、多視窗和多裝置點擊,斷言服務端只產生一次確認狀態轉換。

公開來源

同類題目