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).
If a cached response to a GET request contains both of:
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.
I imagine there’s lots of cases to work out, e.g.:
beforeunloadfired? What if a handler calls
- 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.
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).
- 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.
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).
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.
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!