Angular Service Worker在Safari登出后卡顿问题排查求助
iPhone Safari下Angular PWA登出卡顿的排查与解决
问题背景
基于Angular 14的PWA应用,部署在Azure Blob Storage静态网站,使用Azure AD B2C + MSAL实现认证。调用msalService.logoutRedirect()时,仅iPhone Safari在锁屏数分钟后会出现浏览器冻结、持续网络请求的卡顿问题,禁用Angular Service Worker(SW)后恢复正常,推测与SW处理第三方字体缓存有关。
核心排查与解决方案
1. 修复谷歌字体的SW缓存配置
当前ngsw-config.json未包含跨域的谷歌字体资源,Angular SW默认不缓存跨域内容。锁屏后Safari可能清理了系统缓存,SW拦截字体请求时找不到缓存,陷入无限重试循环。
修改ngsw-config.json,添加dataGroups配置专门处理谷歌字体:
{ "$schema": "./node_modules/@angular/service-worker/config/schema.json", "index": "/index.html", "assetGroups": [ // 原有的assetGroups配置保持不变 { "name": "app", "installMode": "prefetch", "resources": { "files": [ "/favicon.ico", "/index.html", "/manifest.webmanifest", "/*.css", "/*.js" ] } }, { "name": "assets", "installMode": "lazy", "updateMode": "prefetch", "resources": { "files": [ "/assets/**", "/*.(eot|svg|cur|jpg|png|webp|gif|otf|ttf|woff|woff2|ani)" ] } } ], // 新增dataGroups处理谷歌字体 "dataGroups": [ { "name": "google-fonts", "urls": [ "https://fonts.googleapis.com/**", "https://fonts.gstatic.com/**" ], "cacheConfig": { "maxSize": 50, "maxAge": "7d", "strategy": "freshness" } } ] }
freshness策略优先尝试网络请求,失败时回退到缓存,避免SW因缓存缺失卡住;同时明确允许缓存跨域字体资源。
2. 登出流程中临时绕过SW
针对Safari环境,在执行登出前临时注销SW,避免其干扰登出跳转流程:
async logout() { // 检测是否为Safari浏览器 if (/^((?!chrome|android).)*safari/i.test(navigator.userAgent)) { const registration = await navigator.serviceWorker.getRegistration(); if (registration) { // 临时注销SW await registration.unregister(); } } this.msalService.logoutRedirect(); }
- 用户从登出页面返回时,SW会自动重新注册,不影响PWA的正常功能。
3. Safari专属SW调试技巧
无需直接调试2000行的ngsw-worker.js,用远程调试提前监控请求:
- 开启iPhone的「设置」→「Safari浏览器」→「高级」→「Web检查器」
- Mac端Safari开启「开发」菜单,选择对应iPhone设备的应用页面,实时监控SW的
fetch事件日志 - 提前在构建后的
ngsw-worker.js中添加日志(位于dist目录):// 在fetch事件处理开头添加 self.addEventListener('fetch', (event) => { console.log('SW处理请求:', event.request.url); // 原有代码保持不变 }); - 卡顿发生时,通过远程控制台确认是否卡在谷歌字体的请求上。
4. 缓存状态验证的替代方法
当ngsw/state无法访问时,用代码主动检查SW缓存内容:
async checkSWCache() { const cache = await caches.open('ngsw:assets:cache'); const cachedUrls = (await cache.keys()).map(key => key.url); console.log('SW缓存的资源:', cachedUrls); }
- 在应用正常状态下执行,确认谷歌字体是否被正确缓存,以及锁屏后是否被清理。
内容的提问来源于stack exchange,提问作者killexe
相关产品推荐
相关产品推荐

