20

I'm using Chrome 40 (so something nice and modern).

Cache-Control: max-age=0, no-cache is set on all pages - so I expect the browser to only use something from its cache if it has first checked with the server and gotten a 304 Not Modified response.

However on pressing the back button the browser merrily hits its own cache without checking with the server.

If I open the same page, as I reached with the back button, in a new tab then it does check with the server (and gets a 303 See Other response as things have changed).

See the screen captures below showing the output for the two different cases from the Network tab of the Chrome Developer Tools.

I thought I could use max-age=0, no-cache as a lighter weight alternative to no-store where I don't want users seeing stale data via the back button (but where the data is non-valuable and so can be cached).

My understanding of no-cache (see here and here on SO) is that the browser must always revalidate all responses. So why doesn't Chrome do this when using the back button?

Is no-store the only option?


200 response (from cache) on pressing back button:

enter image description here

303 response on requesting the same page in a new tab:

enter image description here

Community
  • 1
  • 1
George Hawkins
  • 31,923
  • 5
  • 27
  • 40

3 Answers3

29

From http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.1

no-cache

If the no-cache directive does not specify a field-name, then a cache MUST NOT use the response to satisfy a subsequent request without successful revalidation with the origin server. This allows an origin server to prevent caching even by caches that have been configured to return stale responses to client requests.

If the no-cache directive does specify one or more field-names, then a cache MAY use the response to satisfy a subsequent request, subject to any other restrictions on caching. However, the specified field-name(s) MUST NOT be sent in the response to a subsequent request without successful revalidation with the origin server. This allows an origin server to prevent the re-use of certain header fields in a response, while still allowing caching of the rest of the response.

Other than the name implies, no-cache does not require that the response must not be stored in cache. It only specifies that the cached response must not be reused to serve a subsequent request without re-validating, so it's a shorthand for must-revalidate, max-age=0.

It is up to the browser what to qualify as a subsequent request, and to my understanding using the back-button does not. This behavior varies between different browser engines.

no-store forbids the use of the cached response for all requests, not only for subsequent ones.

Note that even with no-store, the RFC actually permits the client to store the response for use in history buffers. That means client may still use a cached response even when no-store has been specified.

Latter behavior covers cases where the page has been recorded with its original page title in the browser history. Another use case is the behavior of various mobile browsers which will not discard the previous page until the following page has fully loaded as the user might want to abort.

For clarification on the the behavior of the back button: It is not subject to any cache header, according to http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.13

User agents often have history mechanisms, such as "Back" buttons and history lists, which can be used to redisplay an entity retrieved earlier in a session.

History mechanisms and caches are different. In particular history mechanisms SHOULD NOT try to show a semantically transparent view of the current state of a resource. Rather, a history mechanism is meant to show exactly what the user saw at the time when the resource was retrieved.

By default, an expiration time does not apply to history mechanisms. If the entity is still in storage, a history mechanism SHOULD display it even if the entity has expired, unless the user has specifically configured the agent to refresh expired history documents.

That means that disrespecting any cache control headers when using the back button is the recommended behavior. If your browser happens to honor a backdated expiration date or applies the no-store directive not only to the browser cache but also to the history, it's actually already departing from that recommendation.

For how to solve it:
You can't, and you are not supposed to. If the user is returning to a previously visited page, most browsers will even try to restore the viewport. You may use deferred mechanism like AJAX to refresh content if this was the original behavior before the user left the page, but otherwise you should not even modify the content.

Community
  • 1
  • 1
Ext3h
  • 4,599
  • 12
  • 39
  • This sounds like a reasonable explanation but is it based on any sources? You say that it's "up to the browser what to qualify as a subsequent request" - but is this formally stated anywhere? Without references this just feels like a good post-hoc justification for Chrome's behavior. – George Hawkins Mar 25 '15 at 15:38
  • 3
    @GeorgeHawkins http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.13 `History mechanisms and caches are different. In particular history mechanisms SHOULD NOT try to show a semantically transparent view of the current state of a resource. Rather, a history mechanism is meant to show exactly what the user saw at the time when the resource was retrieved.` – Ext3h Mar 25 '15 at 15:50
  • Does that imply that every AJAX request that modifies the resource: e.g. `PUT`, `PATCH` must always be accompanied by a `GET` request to re-fetch the resource? so that the history mechanism will restore the view at the time the user exits it? This kinda defeats the purpose of caching, which is meant to reduce requests. – kakarukeys Jul 22 '20 at 16:02
1

Looks like this is a known 'quirk' in Chrome with using the back button. There is a good discussion of the issue in the bug report for it here:

https://code.google.com/p/chromium/issues/detail?id=28035

Sadly it looks like most people reverted to using no-store instead.

I expect though that most users are used to an experience of not getting a full page refresh using the back button. If you think about most Angular or Backbone apps that manage the back action themselves so that you just refresh content and not the page. With this in mind I suspect that having the customer refresh or get updates when they come back might not be that unexpected.

JodiMiddleton
  • 300
  • 1
  • 8
  • I hadn't thought about the implications for Angular etc. and this is actually the best justification I've seen for the current behavior. Thanks :) It'd be nice if we could find a reference from Google indicating the current behavior was a conscious decision based on something like this. Google don't seem to go out of their way to clarify anything in their responses to the bug you reference (in fact I think they misunderstood it - they've merged it with what feels like an unrelated issue to me). – George Hawkins Mar 25 '15 at 15:36
  • 1
    I wish I could split the bounty but apparently this is [not allowed](http://meta.stackexchange.com/questions/2786/accept-multiple-answers-or-split-bounty-among-several-users). Your bug link and comment of Angular were informative but Ext3h's answer came closer to pointing up why the behavior is _allowed_ to be like this. – George Hawkins Mar 26 '15 at 10:27
1

Have you tried using the full old set of no-cache headers?

<meta http-equiv="cache-control" content="max-age=0" />
<meta http-equiv="cache-control" content="no-cache" />
<meta http-equiv="expires" content="0" />
<meta http-equiv="expires" content="Tue, 01 Jan 1980 1:00:00 GMT" />
<meta http-equiv="pragma" content="no-cache" />

This seems to work all the time, unless you are running a "pushState" web.

Ingmars
  • 938
  • 5
  • 10