Может ли обслуживающий персонал кэшировать POST-запросы?

Я попытался кэшировать POST-запрос в рабочем приложении для события fetch.

Я использовал cache.put(event.request, response), но возвращенное обещание было отклонено с помощью TypeError: Invalid request method POST..

Когда я пытался попасть в тот же API POST, caches.match(event.request) давал мне undefined.

Но когда я делал то же самое для методов GET, он работал: caches.match(event.request) для запроса GET давал мне ответ.

Может ли обслуживающий персонал кэшировать POST-запросы? В случае, если они не могут, какой подход мы можем использовать, чтобы сделать приложения действительно автономными?

Ответ 1

Вы не можете кэшировать POST-запросы, используя Cache API. См. Https://w3c.github.io/ServiceWorker/#cache-put (пункт 4).

Связанное обсуждение есть в репозитории спецификаций: https://github.com/slightlyoff/ServiceWorker/issues/693.

Интересное решение представлено в Поваренной книге ServiceWorker: https://serviceworke.rs/request-deferrer.html По сути, решение сериализует запросы к IndexedDB.

Ответ 2

Я использовал следующее решение в недавнем проекте с API-интерфейсом GraphQL: я кэшировал все ответы маршрутов 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 body: e.g. serialize it to a string */
}

Вот полный код для моего конкретного решения, используя Dexie.js как IndexedDB-wrapper. Не стесняйтесь использовать его!

Ответ 3

Если вы говорите о данных формы, вы можете перехватить событие выборки и прочитать данные формы так же, как показано ниже, а затем сохранить данные в 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... )
      }
})

Ответ 4

Другой подход к предоставлению полного автономного режима может быть получен с помощью автономного сохранения Cloud Firestore.

POST/PUT-запросы выполняются в локальной кэшированной базе данных, а затем автоматически синхронизируются с сервером, как только пользователь восстанавливает подключение к Интернету (обратите внимание, что существует ограничение в 500 автономных запросов).

Следуя этому решению, следует учитывать еще один аспект, заключающийся в том, что если у нескольких пользователей есть автономные изменения, которые синхронизируются одновременно, нет гарантии, что изменения будут выполнены в правильном хронологическом порядке на сервере, так как Firestore использует службу "первым пришел - первым обслужен". логика.