使用 Workbox 预缓存 Firebase JS 文件 - 被 CORS 阻止
Precache Firebase JS files with Workbox - blocked by CORS
我正在制作一个使用 Google Firebase 作为后端的 PWA。我已经设置了 Workbox 来制作我的 Service Worker,它正确地预缓存了我需要的所有文件……除了来自 gstatic.com 的 firebase JS 文件。我正在使用 Onsen UI 并且 Workbox 设法预缓存了 Onsen 第 3 方文件,所以它一定与 Firebase 的有关。
这些是包含 Firebase 文件的 HTML 标签:
<script src="https://www.gstatic.com/firebasejs/7.0.0/firebase-app.js"></script>
<script crossorigin="anonymous" src="https://www.gstatic.com/firebasejs/7.0.0/firebase-firestore.js"></script>
<script src="/__/firebase/7.0.0/firebase-auth.js"></script>
<script crossorigin="anonymous" src="https://www.gstatic.com/firebasejs/7.0.0/firebase-analytics.js"></script>
这是目前为止的 Workbox service worker:
importScripts('https://storage.googleapis.com/workbox-cdn/releases/4.3.1/workbox-sw.js');
if (workbox) {
console.log(`Yay! Workbox is loaded `);
} else {
console.log(`Boo! Workbox didn't load `);
}
workbox.precaching.precacheAndRoute([
'/index.html',
'/auth.js',
'/script.js',
'https://unpkg.com/onsenui/css/onsenui.css',
'https://unpkg.com/onsenui/css/onsen-css-components.min.css',
'https://unpkg.com/onsenui/js/onsenui.min.js',
'/__/firebase/7.0.0/firebase-auth.js',
'https://www.gstatic.com/firebasejs/7.0.0/firebase-app.js',
'https://www.gstatic.com/firebasejs/7.0.0/firebase-firestore.js',
'https://www.gstatic.com/firebasejs/7.0.0/firebase-analytics.js'
]);
workbox.routing.registerRoute(
/\.(?:png|jpg|jpeg|svg|gif)$/,
new workbox.strategies.CacheFirst({
cacheName: 'image-cache',
})
);
workbox.routing.registerRoute(
/\.(?:js|css|html)$/,
new workbox.strategies.CacheFirst({
cacheName: 'src-cache',
})
);
这是我尝试 运行 时控制台中的错误之一:
Access to fetch at 'https://www.gstatic.com/firebasejs/7.0.0/firebase-app.js' from origin 'http://localhost:5000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
Uncaught (in promise) TypeError: Failed to fetch
谁能告诉我如何解决这个问题?
问题不在于 Firebase 本身。您的错误消息表明 gstatic.com 服务器不为该资源提供 CORS header。如果没有该 CORS header,工作箱将无法检查该资源的响应。这使得缓存非常困难。
在a GitHub issue for workbox 上有一些关于您在此处尝试执行的操作(从 CDN 预缓存)的讨论。相关句子是:
One complication is that this should only work if the CDN supports CORS, because precaching opaque responses and serving them cache-first isn't a good practice.
workbox doco 详细讨论了缓存和不透明响应问题:
This response would cache the opaque response and serve it up from that point onwards. The problem is that if that request fails for any reason, Workbox won’t be able to detect this and will continue to serve up the broken response. The user will be in a broken state.
在你的情况下,如果你可以强制工作箱缓存来自 CDN 的资源(我不认为你可以)那么它有可能缓存错误response 或至少 workbox 不知道何时有新版本的资源可用,因为它无法检查响应。
选项 1
如果您使用 webpack 之类的东西来捆绑您的代码,那么您可以 不 使用 CDN,而是捆绑 firebase code in with your app. You can look at using a build tool 以自动生成预缓存清单.
选项 2
从 html 文件的 <script>
标签中删除那些 crossorigin="anonymous"
属性。然后从预缓存清单中删除底部的 3 个项目(对于 gstatic.com/firebase...)。这意味着您不需要 CORS headers,而且这些文件不会在 PWA 意义上被预缓存。不过,它们仍应由您的浏览器缓存,因此希望它仍然有效。
顺便说一句,我也在开发一个使用 Onsen 的 PWA :D
我正在制作一个使用 Google Firebase 作为后端的 PWA。我已经设置了 Workbox 来制作我的 Service Worker,它正确地预缓存了我需要的所有文件……除了来自 gstatic.com 的 firebase JS 文件。我正在使用 Onsen UI 并且 Workbox 设法预缓存了 Onsen 第 3 方文件,所以它一定与 Firebase 的有关。
这些是包含 Firebase 文件的 HTML 标签:
<script src="https://www.gstatic.com/firebasejs/7.0.0/firebase-app.js"></script>
<script crossorigin="anonymous" src="https://www.gstatic.com/firebasejs/7.0.0/firebase-firestore.js"></script>
<script src="/__/firebase/7.0.0/firebase-auth.js"></script>
<script crossorigin="anonymous" src="https://www.gstatic.com/firebasejs/7.0.0/firebase-analytics.js"></script>
这是目前为止的 Workbox service worker:
importScripts('https://storage.googleapis.com/workbox-cdn/releases/4.3.1/workbox-sw.js');
if (workbox) {
console.log(`Yay! Workbox is loaded `);
} else {
console.log(`Boo! Workbox didn't load `);
}
workbox.precaching.precacheAndRoute([
'/index.html',
'/auth.js',
'/script.js',
'https://unpkg.com/onsenui/css/onsenui.css',
'https://unpkg.com/onsenui/css/onsen-css-components.min.css',
'https://unpkg.com/onsenui/js/onsenui.min.js',
'/__/firebase/7.0.0/firebase-auth.js',
'https://www.gstatic.com/firebasejs/7.0.0/firebase-app.js',
'https://www.gstatic.com/firebasejs/7.0.0/firebase-firestore.js',
'https://www.gstatic.com/firebasejs/7.0.0/firebase-analytics.js'
]);
workbox.routing.registerRoute(
/\.(?:png|jpg|jpeg|svg|gif)$/,
new workbox.strategies.CacheFirst({
cacheName: 'image-cache',
})
);
workbox.routing.registerRoute(
/\.(?:js|css|html)$/,
new workbox.strategies.CacheFirst({
cacheName: 'src-cache',
})
);
这是我尝试 运行 时控制台中的错误之一:
Access to fetch at 'https://www.gstatic.com/firebasejs/7.0.0/firebase-app.js' from origin 'http://localhost:5000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
Uncaught (in promise) TypeError: Failed to fetch
谁能告诉我如何解决这个问题?
问题不在于 Firebase 本身。您的错误消息表明 gstatic.com 服务器不为该资源提供 CORS header。如果没有该 CORS header,工作箱将无法检查该资源的响应。这使得缓存非常困难。
在a GitHub issue for workbox 上有一些关于您在此处尝试执行的操作(从 CDN 预缓存)的讨论。相关句子是:
One complication is that this should only work if the CDN supports CORS, because precaching opaque responses and serving them cache-first isn't a good practice.
workbox doco 详细讨论了缓存和不透明响应问题:
This response would cache the opaque response and serve it up from that point onwards. The problem is that if that request fails for any reason, Workbox won’t be able to detect this and will continue to serve up the broken response. The user will be in a broken state.
在你的情况下,如果你可以强制工作箱缓存来自 CDN 的资源(我不认为你可以)那么它有可能缓存错误response 或至少 workbox 不知道何时有新版本的资源可用,因为它无法检查响应。
选项 1
如果您使用 webpack 之类的东西来捆绑您的代码,那么您可以 不 使用 CDN,而是捆绑 firebase code in with your app. You can look at using a build tool 以自动生成预缓存清单.
选项 2
从 html 文件的 <script>
标签中删除那些 crossorigin="anonymous"
属性。然后从预缓存清单中删除底部的 3 个项目(对于 gstatic.com/firebase...)。这意味着您不需要 CORS headers,而且这些文件不会在 PWA 意义上被预缓存。不过,它们仍应由您的浏览器缓存,因此希望它仍然有效。
顺便说一句,我也在开发一个使用 Onsen 的 PWA :D