// Service Worker for PWA functionality const CACHE_NAME = 'it-hardware-ranking-v1' const RUNTIME_CACHE = 'it-hardware-ranking-runtime' // 需要预缓存的资源列表 const STATIC_CACHE_URLS = [ '/', '/index.html', '/manifest.json', '/favicon.ico', // 添加其他需要预缓存的静态资源 ] // 需要网络优先的资源 const NETWORK_FIRST_URLS = [ '/api/', // 添加其他需要网络优先的API路径 ] // 需要缓存优先的资源 const CACHE_FIRST_URLS = [ '/static/', '/assets/', // 添加其他需要缓存优先的静态资源路径 ] // 安装事件 - 预缓存静态资源 self.addEventListener('install', (event) => { console.log('[SW] Install event triggered') event.waitUntil( caches.open(CACHE_NAME) .then((cache) => { console.log('[SW] Caching static resources') return cache.addAll(STATIC_CACHE_URLS) }) .then(() => { console.log('[SW] Static resources cached successfully') // 强制激活新的Service Worker return self.skipWaiting() }) .catch((error) => { console.error('[SW] Failed to cache static resources:', error) }) ) }) // 激活事件 - 清理旧缓存 self.addEventListener('activate', (event) => { console.log('[SW] Activate event triggered') event.waitUntil( caches.keys() .then((cacheNames) => { return Promise.all( cacheNames.map((cacheName) => { // 删除旧版本的缓存 if (cacheName !== CACHE_NAME && cacheName !== RUNTIME_CACHE) { console.log('[SW] Deleting old cache:', cacheName) return caches.delete(cacheName) } }) ) }) .then(() => { console.log('[SW] Old caches cleaned up') // 立即控制所有客户端 return self.clients.claim() }) .catch((error) => { console.error('[SW] Failed to clean up old caches:', error) }) ) }) // 网络请求拦截 self.addEventListener('fetch', (event) => { const { request } = event const url = new URL(request.url) // 跳过非HTTP(S)请求 if (!url.protocol.startsWith('http')) { return } // 跳过Chrome扩展请求 if (url.protocol === 'chrome-extension:') { return } // 根据请求URL选择缓存策略 if (isNetworkFirst(url)) { // 网络优先策略 event.respondWith(networkFirst(request)) } else if (isCacheFirst(url)) { // 缓存优先策略 event.respondWith(cacheFirst(request)) } else { // 缓存优先,网络作为后备策略 event.respondWith(staleWhileRevalidate(request)) } }) // 判断是否使用网络优先策略 function isNetworkFirst(url) { return NETWORK_FIRST_URLS.some(path => url.pathname.startsWith(path)) } // 判断是否使用缓存优先策略 function isCacheFirst(url) { return CACHE_FIRST_URLS.some(path => url.pathname.startsWith(path)) } // 网络优先策略 async function networkFirst(request) { const cache = await caches.open(RUNTIME_CACHE) try { // 尝试从网络获取 const response = await fetch(request) // 如果响应成功,缓存它 if (response.ok) { cache.put(request, response.clone()) } return response } catch (error) { console.log('[SW] Network request failed, trying cache:', error) // 网络失败,尝试从缓存获取 const cachedResponse = await cache.match(request) if (cachedResponse) { return cachedResponse } // 如果缓存也没有,返回离线页面 return new Response('离线状态,请检查网络连接', { status: 503, statusText: 'Service Unavailable' }) } } // 缓存优先策略 async function cacheFirst(request) { const cache = await caches.open(RUNTIME_CACHE) const cachedResponse = await cache.match(request) if (cachedResponse) { return cachedResponse } try { // 缓存中没有,从网络获取 const response = await fetch(request) // 如果响应成功,缓存它 if (response.ok) { cache.put(request, response.clone()) } return response } catch (error) { console.log('[SW] Network request failed:', error) // 返回错误响应 return new Response('网络请求失败', { status: 500, statusText: 'Internal Server Error' }) } } // 缓存优先,网络作为后备策略 async function staleWhileRevalidate(request) { const cache = await caches.open(RUNTIME_CACHE) const cachedResponse = await cache.match(request) // 在后台发起网络请求 const fetchPromise = fetch(request).then((response) => { // 如果响应成功,更新缓存 if (response.ok) { cache.put(request, response.clone()) } return response }).catch((error) => { console.log('[SW] Background fetch failed:', error) // 返回错误响应,但不影响缓存的响应 return new Response('网络请求失败', { status: 500, statusText: 'Internal Server Error' }) }) // 如果有缓存,立即返回缓存 if (cachedResponse) { return cachedResponse } // 没有缓存,等待网络请求 return fetchPromise } // 后台同步事件 self.addEventListener('sync', (event) => { console.log('[SW] Background sync event:', event.tag) if (event.tag === 'background-sync') { event.waitUntil(doBackgroundSync()) } }) // 执行后台同步 async function doBackgroundSync() { try { // 这里可以执行需要在网络恢复时同步的任务 console.log('[SW] Performing background sync') // 例如:同步离线时的数据 // await syncOfflineData() } catch (error) { console.error('[SW] Background sync failed:', error) } } // 推送通知事件 self.addEventListener('push', (event) => { console.log('[SW] Push event received') if (!event.data) { return } const options = event.data.json() event.waitUntil( self.registration.showNotification(options.title || '新消息', { body: options.body || '您有新消息', icon: options.icon || '/favicon.ico', badge: options.badge || '/favicon.ico', data: options.data || {}, actions: options.actions || [] }) ) }) // 通知点击事件 self.addEventListener('notificationclick', (event) => { console.log('[SW] Notification click event') event.notification.close() // 处理通知点击 if (event.action) { // 处理特定的操作按钮点击 handleNotificationAction(event.action, event.notification.data) } else { // 处理通知主体点击 handleNotificationClick(event.notification.data) } }) // 处理通知点击 function handleNotificationClick(data) { // 打开应用或特定页面 event.waitUntil( clients.openWindow(data.url || '/') ) } // 处理通知操作 function handleNotificationAction(action, data) { // 根据不同的操作执行不同的逻辑 switch (action) { case 'view': clients.openWindow(data.url || '/') break case 'dismiss': // 关闭通知,无需其他操作 break default: console.log('[SW] Unknown notification action:', action) } }