Although according to the accepted answer "You can't cache POST requests using the Cache API"... it seems that actually you can.
Maybe there are good reasons to avoid doing so, as a routine, because of the nature of POST
requests... but if you have to, then it seems to be perfectly possible. In my case, I'd rather be using GET
(with relevant info for the GET
operation in the URL) but instead I'm having to post the relevant info via the body of a POST
to avoid (sometimes) running into URL length limits. But effectively I'm just using POST
as a workaround here, and in my eyes I'm still really using it as a GET
, so it seems reasonable that in this situation I should be able to cache responses to my POST
requests... just using a cache key based on what is in the POST
body rather than what is in the GET
URL.
All you have to do is to clone the POST
request and convert it into a GET
request... used the cloned GET
request as the basis for caching in the service worker cache, but use the original POST
request to get the response that is to be cached.
Something along the lines of the following:
if (request.method.toUpperCase() === "POST") {
// get the body text...
const body = await request.clone().text();
// create a new URL for the purposes of a cache key...
const cacheUrl = new URL(request.url);
// create an augmented URL by appending the body to the original pathname...
cacheUrl.pathname = cacheUrl.pathname + body;
// convert the request to a GET to be able to cache it...
const cacheRequest = new Request(cacheUrl.toString(), {
headers: request.headers,
method: "GET"
});
// get cache...
const cache = caches.default;
// check if there is a cached response in the cache based on the cloned GET request (for the cache key) NOT the original POST request...
let response = await cache.match(cacheRequest);
// if not, fetch the response using the original POST request...
if (!response) {
response = await fetch(request);
// put the response into the cache using the cloned GET request (for the cache key) NOT the original POST request...
event.waitUntil(cache.put(cacheRequest, response.clone()));
}
return response;
}
In my case I'm not actually passing a cloned request into the cache API, but instead just passing a string cache key, so it's not actually necessary to create a dummy GET
request at all... I'm effectively just passing the derived string cacheUrl.pathname
directly to cache.match()
and cache.put()
... they don't reject this as a POST
request because it's just a string, not a request.