When caching assets at runtime, there's no one-size-fits-all rule for whether a given response is "valid" and eligible for being saved and reused.
The workbox-cacheable-response
module provides a standard way of determining
whether a response should be cached based on its
numeric status code,
the presence of a
header
with a specific value, or a combination of the two.
Caching Based on Status Codes
You can configure a Workbox strategy to consider
a set of status codes as being eligible for caching by adding a
CacheableResponsePlugin
instance to a strategy's plugins
parameter:
import {registerRoute} from 'workbox-routing';
import {CacheFirst} from 'workbox-strategies';
import {CacheableResponsePlugin} from 'workbox-cacheable-response';
registerRoute(
({url}) =>
url.origin === 'https://third-party.example.com' &&
url.pathname.startsWith('/images/'),
new CacheFirst({
cacheName: 'image-cache',
plugins: [
new CacheableResponsePlugin({
statuses: [0, 200],
}),
],
})
);
This configuration tells Workbox that when processing responses for
requests against https://third-party.example.com/images/
, cache any requests
with a status code of 0
or 200
.
Caching Based on Headers
You can configure a Workbox strategy to check
for the presence of specific header values as criteria for being added
to the cache by setting the headers
object when constructing the plugin:
import {registerRoute} from 'workbox-routing';
import {StaleWhileRevalidate} from 'workbox-strategies';
import {CacheableResponsePlugin} from 'workbox-cacheable-response';
registerRoute(
({url}) => url.pathname.startsWith('/path/to/api/'),
new StaleWhileRevalidate({
cacheName: 'api-cache',
plugins: [
new CacheableResponsePlugin({
headers: {
'X-Is-Cacheable': 'true',
},
}),
],
})
);
When processing responses for request URLs containing /path/to/api/
,
take a look at the header named X-Is-Cacheable
(which would be added
to the response by the server). If that header is present, and if it is
set to a value of 'true', then the response can be cached.
If multiple headers are specified, then only one of the headers needs to match the associated values.
Caching Based on Headers and Status Codes
You can mix together both status and header configuration. Both conditions must be met in order for a response to be considered cacheable; in other words, the response must have one of the configured status codes, and it must have at least one of the provided headers.
import {registerRoute} from 'workbox-routing';
import {StaleWhileRevalidate} from 'workbox-strategies';
import {CacheableResponsePlugin} from 'workbox-cacheable-response';
registerRoute(
({url}) => url.pathname.startsWith('/path/to/api/'),
new StaleWhileRevalidate({
cacheName: 'api-cache',
plugins: [
new CacheableResponsePlugin({
statuses: [200, 404],
headers: {
'X-Is-Cacheable': 'true',
},
}),
],
})
);
What Are the Defaults?
If you use one of Workbox's built-in strategies without explicitly
configuring a cacheableResponse.CacheableResponsePlugin
, the following default criteria is
used to determine whether a response received from the network should
be cached:
- staleWhileRevalidate and networkFirst: Responses with a status of
0
(i.e. opaque responses) or200
are considered cacheable. - cacheFirst: Responses with a status of
200
are considered cacheable.
By default, response headers are not used to determine cacheability.
Why are there Different Defaults?
The defaults vary around whether responses with a status of 0
(i.e. opaque responses)
will end up cached. Due to the "black box" nature of opaque responses,
it's not possible for the service worker to know whether the response
is valid, or whether it reflects an error response returned from the
cross-origin server.
For strategies that include some means of updating the cached response, like staleWhileRevalidate and networkFirst, the risk of caching a transient error response is mitigated by the fact that the next time the cache is updated, a proper, successful response will hopefully be used.
For strategies that involve caching the first response received and
reusing that cached response indefinitely, the repercussions of a
transient error getting cached and reused are more severe. To err on the
safe side by default, cacheFirst will refuse to save a response unless it
has a status code of 200
.
Advanced Usage
If you want to use the same caching logic outside of a Workbox strategy, you
can use the CacheableResponse
class directly.
import {CacheableResponse} from 'workbox-cacheable-response';
const cacheable = new CacheableResponse({
statuses: [0, 200],
headers: {
'X-Is-Cacheable': 'true',
},
});
const response = await fetch('/path/to/api');
if (cacheable.isResponseCacheable(response)) {
const cache = await caches.open('api-cache');
cache.put(response.url, response);
} else {
// Do something when the response can't be cached.
}
Types
CacheableResponse
This class allows you to set up rules determining what
status codes and/or headers need to be present in order for a
Response
to be considered cacheable.
Properties
-
constructor
void
To construct a new CacheableResponse instance you must provide at least one of the
config
properties.If both
statuses
andheaders
are specified, then both conditions must be met for theResponse
to be considered cacheable.The
constructor
function looks like:(config?: CacheableResponseOptions) => {...}
-
config
CacheableResponseOptions optional
-
returns
-
-
isResponseCacheable
void
Checks a response to see whether it's cacheable or not, based on this object's configuration.
The
isResponseCacheable
function looks like:(response: Response) => {...}
-
response
Response
The response whose cacheability is being checked.
-
returns
boolean
true
if theResponse
is cacheable, andfalse
otherwise.
-
CacheableResponseOptions
Properties
-
headers
object optional
-
statuses
number[] optional
CacheableResponsePlugin
A class implementing the cacheWillUpdate
lifecycle callback. This makes it
easier to add in cacheability checks to requests made via Workbox's built-in
strategies.
Properties
-
constructor
void
To construct a new CacheableResponsePlugin instance you must provide at least one of the
config
properties.If both
statuses
andheaders
are specified, then both conditions must be met for theResponse
to be considered cacheable.The
constructor
function looks like:(config: CacheableResponseOptions) => {...}
-
config
-
returns
-