Javascript 服务工作者可以缓存 POST 请求吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/35270702/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 17:30:17  来源:igfitidea点击:

Can service workers cache POST requests?

javascriptpostrequestservice-workerpwa

提问by Aniket

I tried to cache a POST request in a service worker on fetch event.

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

I used cache.put(event.request, response), but the returned promise was rejected with TypeError: Invalid request method POST..

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

When I tried to hit the same POST API, caches.match(event.request)was giving me undefined.

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

But when I did the same for GET methods, it worked: caches.match(event.request)for a GET request was giving me a response.

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

Can service workers cache POST requests? In case they can't, what approach can we use to make apps truly offline?

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

回答by Marco

You can't cache POST requests using the Cache API. See https://w3c.github.io/ServiceWorker/#cache-put(point 4).

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

There's a related discussion in the spec repository: https://github.com/slightlyoff/ServiceWorker/issues/693

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

An interesting solution is the one presented in the ServiceWorker Cookbook: https://serviceworke.rs/request-deferrer.htmlBasically, the solution serializes requests to IndexedDB.

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

回答by A. Kabachnik

I've used the following solution in a recent project with a GraphQL API: I cached all responses from API routes in an IndexedDB object store using a serialized representation of the Request as cache key. Then I used the cache as a fallback if the network was unavailable:

我在最近的一个带有 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 */
}

Here is the full codefor my specific solution using Dexie.js as IndexedDB-wrapper. Feel free to use it!

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

回答by Roman Gherta

If you are talking about form data, then you could intercept the fetch event and read the form data in a similar way as below and then save the data in indexedDB.

如果您正在谈论表单数据,那么您可以拦截 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... )
      }
})

回答by Francesco

Another approach to provide a full offlineexperience can be obtained by using Cloud Firestore offline persistence.

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

POST / PUT requests are executed on the local cached database and then automatically synchronised to the server as soon as the user restores its internet connectivity (note though that there is a limit of 500 offline requests).

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

Another aspect to be taken into account by following this solution is that if multiple users have offline changes that get concurrently synchronised, there is no warranty that the changes will be executed in the right chronological order on the server as Firestore uses a first come first servedlogic.

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

回答by Oleksii Kyslytsyn

According to https://w3c.github.io/ServiceWorker/#cache-put(point 4).

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

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