Can service workers cache POST requests?

前端 未结 5 1550
猫巷女王i
猫巷女王i 2020-12-01 04:30

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

I used cache.put(event.request, response), but the returned promise was rejected wit

相关标签:
5条回答
  • 2020-12-01 05:04

    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:

    // 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 code for my specific solution using Dexie.js as IndexedDB-wrapper. Feel free to use it!

    0 讨论(0)
  • 2020-12-01 05:05

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

            if(request.method !== "GET") {
                return Promise.reject('no-match')
            }
    
    0 讨论(0)
  • 2020-12-01 05:14

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

    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).

    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 served logic.

    0 讨论(0)
  • 2020-12-01 05:18

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

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

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

    0 讨论(0)
  • 2020-12-01 05:22

    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.

    //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... )
          }
    })
    
    0 讨论(0)
提交回复
热议问题