files/en-us/web/api/fetchevent/respondwith/index.md
{{APIRef("Service Workers API")}}{{AvailableInWorkers("service")}}
The respondWith() method of
{{domxref("FetchEvent")}} prevents the browser's default fetch handling, and
allows you to provide a promise for a {{domxref("Response")}} yourself.
In most cases you can provide any response that the receiver understands. For example, if an {{HTMLElement('img')}} initiates the request, the response body needs to be image data. For security reasons, there are a few global rules:
"opaque" if the {{domxref("fetchEvent.request")}} object's
{{domxref("request.mode", "mode")}} is "no-cors". This prevents the
leaking of private data."opaqueredirect" if the {{domxref("fetchEvent.request")}}
object's {{domxref("request.mode", "mode")}} is "manual"."cors" if the {{domxref("fetchEvent.request")}} object's
{{domxref("request.mode", "mode")}} is "same-origin".respondWith(response)
response
Response. Otherwise, a network error is returned to Fetch.None ({{jsxref("undefined")}}).
NetworkError {{domxref("DOMException")}}
InvalidStateError {{domxref("DOMException")}}
respondWith() has
already been invoked.From Firefox 59 onwards, when a service worker provides a {{domxref("Response")}} to
FetchEvent.respondWith(), the {{domxref("Response.url")}} value will be
propagated to the intercepted network request as the final resolved URL. If the
{{domxref("Response.url")}} value is the empty string, then the
{{domxref("Request.url","FetchEvent.request.url")}} is used as the final URL.
In the past the {{domxref("Request.url","FetchEvent.request.url")}} was used as the final URL in all cases. The provided {{domxref("Response.url")}} was effectively ignored.
This means, for example, if a service worker intercepts a stylesheet or worker script, then the provided {{domxref("Response.url")}} will be used to resolve any relative {{cssxref("@import")}} or {{domxref("WorkerGlobalScope.importScripts()","importScripts()")}} subresource loads (Firefox bug 1222008).
For most types of network request this change has no impact because you can't observe the final URL. There are a few, though, where it does matter:
self.location
and used as the base URL for relative URLs in the worker script.Note that navigation requests for {{domxref("Window","Windows")}} and {{domxref("HTMLIFrameElement","iframes")}} do NOT use the final URL. The way the HTML specification handles redirects for navigations ends up using the request URL for the resulting {{domxref("Window.location")}}. This means sites can still provide an "alternate" view of a web page when offline without changing the user-visible URL.
This fetch event tries to return a response from the cache API, falling back to the network otherwise.
addEventListener("fetch", (event) => {
// Prevent the default, and handle the request ourselves.
event.respondWith(
(async () => {
// Try to get the response from a cache.
const cachedResponse = await caches.match(event.request);
// Return it if we found one.
if (cachedResponse) return cachedResponse;
// If we didn't find a match in the cache, use the network.
return fetch(event.request);
})(),
);
});
[!NOTE] {{domxref("CacheStorage.match()", "caches.match()")}} is a convenience method. Equivalent functionality is to call {{domxref("cache.match()")}} on each cache (in the order returned by {{domxref("CacheStorage.keys()", "caches.keys()")}}) until a {{domxref("Response")}} is returned.
{{Specifications}}
{{Compat}}