Angular 5项目中用@angular/service-worker缓存Google Maps API失败求助
解决Angular 5 PWA无法缓存Google Maps瓦片的问题
我之前也踩过类似的坑,Angular Service Worker处理第三方动态资源(比如Google Maps的瓦片)确实需要针对性配置,给你几个实用的解决思路:
1. 精准配置dataGroups规则
你之前加了dataGroups但没生效,大概率是URL匹配模式不对。Google Maps的瓦片请求域名和路径有特定格式,得用通配符覆盖所有可能的请求:
打开你的ngsw-config.json,更新dataGroups部分:
"dataGroups": [ { "name": "google-maps-resources", "urls": [ // 匹配Maps的主JS脚本 "https://maps.googleapis.com/maps/api/js/**", // 匹配所有瓦片请求(不同子域名如mt0、mt1等都要覆盖) "https://*.googleapis.com/maps/vt/**", // 可选:如果还有其他Maps相关资源(如标记图标)也加上 "https://*.gstatic.com/maps/vt/**" ], "cacheConfig": { "strategy": "freshness", // 优先用网络,离线用缓存 "maxSize": 2000, // 瓦片数量多,给足够的缓存空间 "maxAge": "14d", // 瓦片不会频繁更新,缓存两周没问题 "timeout": "3s" // 网络超时3秒就用缓存 } } ]
配置完后一定要重新执行ng build --prod,Service Worker只在生产构建时生效。
2. 处理响应头限制
有些Google Maps的响应会带Cache-Control: no-cache或private头,这会阻止Angular Service Worker缓存。如果上面的配置还是没效果,就得用自定义Service Worker来手动缓存这些请求:
- 在项目根目录创建
custom-sw.js,添加以下代码:
self.addEventListener('fetch', (event) => { const requestUrl = new URL(event.request.url); // 只处理Google Maps的瓦片请求 if (requestUrl.hostname.includes('googleapis.com') && requestUrl.pathname.includes('/maps/vt/')) { event.respondWith( caches.open('google-maps-tiles') .then(cache => { // 先尝试网络请求,成功后缓存响应 return fetch(event.request) .then(networkResponse => { cache.put(event.request, networkResponse.clone()); return networkResponse; }) // 网络失败时返回缓存的内容 .catch(() => cache.match(event.request)); }) ); } });
- 修改
angular.json里的Service Worker配置,让构建时包含这个自定义脚本:
"projects": { "your-project-name": { "architect": { "build": { "options": { "serviceWorker": true, "ngswConfigPath": "ngsw-config.json", "assets": [ // 把自定义sw加入资源目录 "src/custom-sw.js" ] } } } } }
- 在
app.module.ts里注册自定义Service Worker:
import { ServiceWorkerModule } from '@angular/service-worker'; import { environment } from '../environments/environment'; @NgModule({ imports: [ ServiceWorkerModule.register('/custom-sw.js', { enabled: environment.production, registrationStrategy: 'registerWhenStable:30000' }) ] })
3. 离线错误处理
你碰到的ERROR Error: Uncaught (in promise): Event报错,本质是离线时请求Maps资源失败但没有捕获Promise异常。可以在Maps初始化的代码里添加错误处理:
import { NgZone } from '@angular/core'; constructor(private ngZone: NgZone) {} initMap() { if (navigator.onLine) { // 在线时加载地图 this.ngZone.runOutsideAngular(() => { // 你的Maps初始化代码 }); } else { // 离线时显示提示 alert('离线状态下无法加载地图,请检查网络连接'); // 或者显示离线地图占位图 } }
测试注意事项
- 每次修改配置后,一定要清空浏览器缓存(Chrome DevTools -> Application -> Clear storage)
- 用
ng serve --prod启动生产环境服务测试,开发环境Service Worker默认不启用 - 在DevTools的Application -> Cache Storage里查看是否有
google-maps-resources或google-maps-tiles的缓存条目
内容的提问来源于stack exchange,提问作者Juri
相关产品推荐
相关产品推荐

