You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何检测用户从DevTools手动注销Service Worker(无需调用自定义Unsubscribe函数)

Detecting Manual Service Worker Unregistration via DevTools (Without Custom Unsubscribe Function)

Got it, so the problem is that users are bypassing your custom Unsubscribe() function by manually unregistering the Service Worker through DevTools, which leaves stale push endpoints lingering in your database. Let’s walk through practical solutions to catch this scenario:

1. Listen for Controller Changes in the Main Page

When a user unregisters the Service Worker, the page’s active controller (the Service Worker controlling the page) will become null. You can listen for the controllerchange event to detect this shift, then validate the current push subscription state and clean up your database if needed:

// Set up the listener when your page initializes
navigator.serviceWorker.addEventListener('controllerchange', async () => {
  // Check if any Service Worker registrations exist
  const registrations = await navigator.serviceWorker.getRegistrations();
  if (registrations.length === 0) {
    // No active registrations = Service Worker was unregistered
    const storedSubscription = JSON.parse(localStorage.getItem('pushSubscription'));
    if (storedSubscription) {
      // Call your backend to remove the stale endpoint
      await fetch('api/push/Unregister', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(storedSubscription)
      });
      // Clear local storage to avoid duplicate cleanup
      localStorage.removeItem('pushSubscription');
    }
  }
});

2. Validate Subscription State on Page Load

Every time the page loads, proactively check if the stored push subscription still matches the active one (if any). If there’s a mismatch or no active subscription exists, sync this with your database:

window.addEventListener('load', async () => {
  const storedSubscription = JSON.parse(localStorage.getItem('pushSubscription'));
  if (!storedSubscription) return;

  try {
    const swReg = await navigator.serviceWorker.ready;
    const currentSubscription = await swReg.pushManager.getSubscription();

    // If no active subscription exists, or endpoints don't match
    if (!currentSubscription || currentSubscription.endpoint !== storedSubscription.endpoint) {
      await fetch('api/push/Unregister', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(storedSubscription)
      });
      localStorage.removeItem('pushSubscription');
    }
  } catch (error) {
    // navigator.serviceWorker.ready failed = no active Service Worker
    await fetch('api/push/Unregister', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(storedSubscription)
    });
    localStorage.removeItem('pushSubscription');
  }
});

3. Bonus: Backend-Side Validation

To cover edge cases (like users clearing local storage), add a validation step on your backend when sending push notifications. If a push request fails with a "410 Gone" or similar error (indicating the endpoint is invalid), automatically remove that endpoint from your database. This acts as a safety net for any missed client-side detections.

Key Notes

  • Store subscriptions locally: Keep a copy of the push subscription in localStorage or sessionStorage so you can reference it when detecting unregistration.
  • Idempotent backend endpoints: Ensure your Unregister API can handle duplicate requests without causing errors (since cleanup might trigger multiple times).
  • Real-time limitations: These client-side methods can’t detect unregistration the exact second it happens (since DevTools unregistration doesn’t fire a direct event), but they’ll catch it on the next page load or controller change—covering most user interactions.

内容的提问来源于stack exchange,提问作者Steinar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.12 04:00:43