Service Worker 可以缓存 POST 请求吗?

IT技术 javascript post request service-worker pwa
2021-03-16 21:12:19

我试图在 fetch 事件中在 service worker 中缓存一个 POST 请求。

我用过cache.put(event.request, response),但返回的Promise被拒绝了TypeError: Invalid request method POST.

当我尝试使用相同的 POST API 时,caches.match(event.request)给了我未定义的信息。

但是当我对 GET 方法做同样的事情时,它起作用了:caches.match(event.request)因为 GET 请求给了我一个响应。

Service Worker 可以缓存 POST 请求吗?如果他们不能,我们可以使用什么方法使应用程序真正离线?

5个回答

您无法使用缓存 API 缓存 POST 请求。请参阅https://w3c.github.io/ServiceWorker/#cache-put(第 4 点)。

规范存储库中有相关讨论:https : //github.com/slightlyoff/ServiceWorker/issues/693

一个有趣的解决方案是 ServiceWorker Cookbook 中提出 的解决方案https : //serviceworke.rs/request-deferrer.html基本上,该解决方案将请求序列化到 IndexedDB。

补丁和删除应该是一样的。您将在 Service Worker 中获得一个“fetch”事件,您可以检查该方法——GET、POST、PATCH、DELETE——并执行您需要执行的任何操作。
2021-05-01 21:12:19
我没有看到任何关于 PATCH 或 DELETE 请求的内容。是一样的吗?
2021-05-02 21:12:19

我在最近的一个带有 GraphQL API 的项目中使用了以下解决方案:我使用请求的序列化表示作为缓存键,将来自 API 路由的所有响应缓存在 IndexedDB 对象存储中。然后,如果网络不可用,我将缓存用作后备:

// ServiceWorker.js
self.addEventListener('fetch', function(event) {
    // We will cache all POST requests to matching URLs
    if(event.request.method === "POST" || event.request.url.href.match(/*...*/)){
        event.respondWith(
            // First try to fetch the request from the server
        fetch(event.request.clone())
            // If it works, put the response into IndexedDB
            .then(function(response) {
                // Compute a unique key for the POST request
                var key = getPostId(request);
                // Create a cache entry
                var entry = {
                    key: key,
                    response: serializeResponse(response),
                    timestamp: Date.now()
                };

                /* ... save entry to IndexedDB ... */

                // Return the (fresh) response
                return response;
            })
            .catch(function() {
                // If it does not work, return the cached response. If the cache does not
                // contain a response for our request, it will give us a 503-response
                var key = getPostId(request);
                var cachedResponse = /* query IndexedDB using the key */;
                return response;
            })
        );
    }
})

function getPostId(request) {
    /* ... compute a unique key for the request incl. it's body: e.g. serialize it to a string */
}

这是我使用 Dexie.js 作为 IndexedDB 包装器的特定解决方案完整代码随意使用它!

我可能会建议你读尽管以下,如果你想推广你的博客进行自我升级的响应范围
2021-04-28 21:12:19
对不起。我已更改答案以包含代码摘要(整个代码很长)。或者我是否希望发布整个代码而不管它的长度?
2021-05-03 21:12:19
虽然此链接可能会回答问题,但最好在此处包含答案的基本部分并提供链接以供参考。如果链接页面发生更改,仅链接答案可能会无效。-来自评论
2021-05-09 21:12:19
一个片段应该没问题。如果您只是发布指向您自己博客的链接,它看起来很像垃圾邮件。现在对我来说似乎好多了
2021-05-16 21:12:19

如果您正在谈论表单数据,那么您可以拦截 fetch 事件并以如下类似的方式读取表单数据,然后将数据保存在 indexedDB 中。

//service-worker.js
self.addEventListener('fetch', function(event) {
      if(event.request.method === "POST"){
         var newObj = {};

               event.request.formData().then(formData => {

                for(var pair of formData.entries()) {
                  var key = pair[0];
                  var value =  pair[1];
                  newObj[key] = value;
                }

              }).then( ...save object in indexedDB... )
      }
})

另一种提供完整离线体验的方法是使用Cloud Firestore 离线持久性

POST / PUT 请求在本地缓存数据库上执行,然后在用户恢复其 Internet 连接后立即自动同步到服务器(请注意,离线请求限制为 500 个)。

遵循此解决方案要考虑的另一个方面是,如果多个用户具有并发同步的离线更改,则无法保证更改将在服务器上按正确的时间顺序执行,因为 Firestore 使用先到先得逻辑。

根据https://w3c.github.io/ServiceWorker/#cache-put(第 4 点)。

        if(request.method !== "GET") {
            return Promise.reject('no-match')
        }