Exposing headers on CORS responses
CORS and its discontents
The concept of CORS requests comes up a lot in my professional life. Much of the time, it's in the context of why a given response is opaque, and how to make that response non-opaque so that it plays nicely with service workers and the Cache Storage API.
Fortunately, many popular third-party APIs and hosts support CORS nowadays, and solving your basic CORS-related mystery normally boils down to, say, adding in the crossorigin
attribute to your <img>
tags.
When CORS is not enough
But while enabling CORS is enough to get back basic information about an HTTP response—like its status code, or access to its body—there's still some information that's locked down by default. The headers exposed on a CORS response, for instance, are limited to the following six "simple" response headers:
Cache-Control
Content-Language
Content-Type
Expires
Last-Modified
Pragma
Some of those headers can come in handy when accessed inside of a service worker, but there's one in particular that can be useful, but isn't exposed by default: Date
.
In particular, if you're using Workbox's cache expiration logic and you provide a maxAgeSeconds
parameter, the Date
of the cached response is checked against the difference between the current time and maxAgeSeconds
. If the Date
is too old, then the cached response will end up being ignored.
But... this logic only works if there's a Date
header exposed on the response. By default, that won't be the case for a CORS response.
Exposition
The workaround, as with so many things related to CORS, involves fiddling with HTTP response headers. You'll either need access to the underlying HTTP server yourself, or you'll need to reach out to your CDN/API provider asking them to make the change.
Setting Access-Control-Expose-Headers: Date
will permit the Date
response header to be visible to your web app's code, and you could include any additional headers there in a comma-separated list.
If you're using your own Express-based web server, the corser
middleware looks pretty reasonable for setting up a working configuration. Their docs include a recipe for configuring the exposed response headers.
Live demo
Here's a quick demonstration, separate from service workers, and using the fantastic https://httpbin.org service to control the Access-Control-Expose-Headers
response header that's returned in a simulated API response. (They support CORS by default, so nothing needs to be done to enable that.)
Check out the log messages in the JavaScript console to see which headers are visible in the response.