使用 @angular/service-worker 缓存 Google Maps API

8
我正在处理一个Angular 5项目,希望通过@angular/service-worker包提供PWA功能。但是我无法缓存和提供Google Maps API请求(例如瓷砖)的响应。当在线时,这些响应没有被缓存,因此在离线时也不能服务。我尝试过以下方法:1.将Maps URL添加到dataGroups中,没有错误,但是也没有缓存。在离线时,会出现以下错误:“ERROR Error: Uncaught (in promise): Event: {“isTrusted”:true} (in the main.bundle.js)”2.将Maps URL添加到assetGroups installMode中,prefetch方式,但当尝试预取时会出现跨域错误:“No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8080' is therefore not allowed access. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.”3.将Maps URL添加到assetGroups installMode中,lazy方式,但结果与installMode: prefetch相同。

其余的数据缓存和服务都很好(静态资源来自本地主机,JSON来自不同端口的本地API端点)。

我的ngsw-config.json看起来像这样:任何指针都将不胜感激。

{
  "index": "/index.html",
  "assetGroups": [{
    "name": "app",
    "installMode": "prefetch",
    "resources": {
      "files": [
        "/favicon.png",
        "/index.html"
      ],
      "versionedFiles": [
        "/*.bundle.css",
        "/*.bundle.js",
        "/*.chunk.js"
      ],
      "urls": [
          "https://fonts.googleapis.com/css?family=Roboto:300,400,500,700",
          "https://fonts.gstatic.com/s/roboto/v18/KFOlCnqEu92Fr1MmEU9fBBc4AMP6lQ.woff2",
          "https://fonts.gstatic.com/s/roboto/v18/KFOmCnqEu92Fr1Mu4mxKKTU1Kg.woff2"
      ]
    }
  }, {
    "name": "assets",
    "installMode": "lazy",
    "updateMode": "prefetch",
    "resources": {
      "files": [
        "/assets/**"
      ]
    }
  }],
    "dataGroups": [{
        "name": "from-api",
        "urls": [
            "/api/restaurants",
            "/img/**",
            "/icons/**",
            "https://maps.googleapis.com/maps/**"
        ],
        "cacheConfig": {
            "maxSize": 100,
            "maxAge": "1d",
            "timeout?": "3s"
        }
    }]
}

如果需要更多信息,我们很乐意提供。


3
缓存可能违反服务条款。请查看第10.5(d)段,其中写道“不得缓存或存储。除了您可以仅为提高Maps API实现的性能而存储有限量的内容(且不是为了防止Google准确跟踪使用情况)外,您不得预取、缓存、索引或存储任何内容以供在服务之外使用...”离线地图功能请求:https://issuetracker.google.com/issues/35827808 - xomena
2个回答

1

我正在使用服务工作者与谷歌地图一起工作,如果我将 "https://maps.googleapis.com/maps/**" 插入到 assetGroups -> urls 中,则可以正常工作:

"urls": [
  "https://fonts.googleapis.com/css?family=Roboto:300,400,500,700",
  "https://fonts.gstatic.com/s/roboto/v18/KFOlCnqEu92Fr1MmEU9fBBc4AMP6lQ.woff2",
  "https://fonts.gstatic.com/s/roboto/v18/KFOmCnqEu92Fr1Mu4mxKKTU1Kg.woff2",
  "https://maps.googleapis.com/maps/**"
]

2
然后,当我尝试预缓存地图数据时,不幸的是我收到了与跨域相关的错误消息:无法加载https://maps.googleapis.com/....:请求的资源上不存在'Access-Control-Allow-Origin'头。因此,不允许从源' http://localhost:8080 '进行访问。如果您需要一个不透明的响应,请将请求模式设置为' no-cors '以禁用CORS获取资源。 - Juri
你是否尝试使用REST(this.$http.get(https://maps.googleapis.com/maps/api/place/details/json?placeid=${googleplacesPlace}&key=${googleplacesToken}).then(response => { })或者google.maps对象(let service = new google.maps.places.PlacesService(this.map);)。请查看此链接:https://stackoverflow.com/questions/45185061/google-places-api-cors。 - Pedro Arantes

1
基本上,Google地图只接受无跨域请求。如果您将请求配置为https:// maps.googleapis.com的无跨域模式,则该请求将被服务器拒绝。
您必须仅允许无跨域请求,然后Google才能确保第三方网站可以自由读取数据,但在修改请求方面受到限制:
所以,我这样做...
var googleMapsAPIJS = "https://maps.googleapis.com/maps/api/js?key =" + YOUR KEY& callback = initMap";
if (requestURL.href = = = googleMapsAPIJS) { 
    event.respondWith(
     fetch( 
    googleMapsAPIJS +"&" + Date.now(), 
        { mode: "no-cors", cache: "no-store" } 
     ).catch( function() {
//so if offline serve my static map
      return caches.match("/offline-map.html"); 
})
); 
}

由于谷歌的服务器返回的地图API JavaScript文件带有标头,导致浏览器总是试图从HTTP缓存中返回它,因此我们必须确保它始终从网络获取。否则,我们的获取将失败,我们会得到谷歌地图控件(来自缓存),但在其下面没有地图(地图数据未被缓存)。我们通过将缓存选项设置为no-store进行获取,从而完全跳过缓存来实现这一点。
不幸的是,在撰写本文时,该选项仍不受所有浏览器支持,因此请向每个请求的查询字符串添加一个缓存破坏时间戳,以确保每个请求都是唯一的并将跳过缓存。我们通过将当前时间附加到每个请求的URL上来实现这一点。
这是我在一本很棒的书中阅读到的解决方案的修改: Ater,Tal。构建渐进式Web应用程序:将本机功能带入浏览器O'Reilly Media。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接