Motivation
To allow content to be cached liberally for performance, for the 99% case, but revocable in the rare event of a strong need, like defacement or security vulnerability.
Cache invalidation is a common feature that intermediaries provide for similar purposes, but it is unavailable to widely distributed caches like the browser’s HTTP cache, any service worker caches, and signed exchanges (which may be served from any HTTPS cache until expiry).
Proposal
If a cached response to a GET request contains both of:
Reload-If-Invalidated: true
-
ETag
and/orLast-Modified
then the browser sends a low-priority conditional request for the same URL along with a request header Purpose: reload
. If the response completes and is not 304, then the browser reloads the resource using the new response.
This would apply to main resources (asynchronously reloading the whole page) and to subresources. For some subresources (e.g. JS), that would necessitate reloading the whole page, while for others (e.g. images), perhaps they could be replaced in-document.
Difficulties
I imagine there’s lots of cases to work out, e.g.:
- Is
beforeunload
fired? What if a handler callspreventDefault
? - If the reload response arrives while the dialog is open for
location.href = prompt("where next?")
, which navigation takes precedent?
Similarly for in-document replacement of images: If the reload response finishes before the original response, is an error
event fired? etc.
Limitations
Because the reload could be a jarring experience to the user, it’s something that the server would want to do sparingly. That is, if the browser sends an If-None-Match
, the server would probably want to 200 only if the etag matches a particularly bad version, e.g. not for a small typo fix. (Presumably an intermediary would send 200 only if the version was explicitly invalidated by its customer, and not if merely expired.)
This differs from a normal conditional fetch, hence the Purpose: reload
. I’m not wild about the developer ergonomics – it’s easy to ignore the Purpose
header and accidentally reload too often. But at least sending Reload-If-Invalidated
is a signal that you’ve made the requisite server changes. And I’m not wild about the alternatives I’d thought of (different HTTP verb, different URL, a special “yes, reload” response code).
Alternatives considered
Signed exchange purge proposals
In the case of SXGs, there have been a couple of proposals. This one differs in a few different ways, which I think help ease the DX of this feature:
- It’s not SXG-specific. This helps ensure it’s deployed correctly because it’ll be triggered in more scenarios.
- It’s optional (for the sake of backwards-compatibility with existing SXGs). This helps the site do a gradual rollout of the feature and monitor for issues.
- It fails open (for the sake of connection resilience). This enables the site to deploy without reducing its availability commitment.
That said, it doesn’t preclude future development of other proposals, for which a different set of properties is wanted.
<script>if (askOriginWhetherToReload()) location.reload()
A few of the disadvantages of a script tag:
- Doesn’t solve the security vulnerability use case; an XSS attack would be able to remove it.
- Often not able to be added by intermediaries; their customers are often OK with them adding HTTP headers but not HTML.
- Doesn’t work for non-HTML resources (e.g. image, PDF).
- The above naive implementation would be slow, resulting in two requests for the updated content. It might be possible to make a more efficient version using SW’s but it’d be difficult and add page weight.
- It would require maintenance to keep its behavior in sync with the web platform (e.g. if a new ETag-like header is added).
Do nothing; recommend short max-age
This would trade off the performance (and possibly serving cost) of the 99% pageview for the freshness of the rare pageview. For some uses, that decision might make sense, but I think the above proposal would be at least as useful, and hence worth adding as an option.
WDYT?
Does the motivation make sense to you? Is this feasible to specify and implement? Do the benefits outweigh the costs? Can you suggest improvements? Thanks!