whatwg / fetch

Fetch Standard
https://fetch.spec.whatwg.org/
Other
2.11k stars 330 forks source link

{cache: "no-cache"} vs Cache-Control: immutable #308

Open ziyunfei opened 8 years ago

ziyunfei commented 8 years ago

Firefox 49 implemented a new extended attribute of the Cache-Control response header - immutable, it has not been standardized yet, see this post for the details.

So here is the conflict: should fetch(aURLWithImmutableCache, {cache: "no-cache"}) send a conditional request first or use the cache directly without sending any request? Currently Firefox's behavior is the latter.

mnot commented 8 years ago

Patrick characterised this as an experiment to gather data; I think putting it into fetch before we have that data is premature.

(that said, I'm pretty excited by immutable, and I know others are too :)

wanderview commented 8 years ago

cc @mcmanus

RobertPlamondon commented 8 years ago

If we think of cache-control fields as being, not facts, but something else, the murkiness may shift in a useful way:

Given where we are in time, I'd make the following assumptions for now:

Given the difficulty in taming the crummy headers coming out of my own Wordpress-powered sites, a certain amount of psychosis in Cache-Control headers is probably to be expected, even in the long term. Back in the RFC 2616 days, the presence of no-cache with max-age etc. served as a bonehead alert, since that wasn't supposed to happen, but the newer spec seems to have dropped this handy indicator.

Robert

wanderview commented 8 years ago

So here is the conflict: should fetch(aURLWithImmutableCache, {cache: "no-cache"}) send a conditional request first or use the cache directly without sending any request? Currently Firefox's behavior is the latter.

Here is how I view it:

  1. fetch(url, { cache: 'no-cache' }) is a signal from the js level to the http cache that resource revalidation is needed at the app level. This is the same as if the reload button in the browser UX is pressed.
  2. The http cache looks in its meta-data for the resource and see the immutable flag. This is interpreted as the resource automatically passing revalidation.
  3. The resource is returned from the http cache directly without any network activity.

If you don't want this behavior, then you can do one of the following:

RobertPlamondon commented 8 years ago

Having worked in the TCP accelerator biz for a while (Orbital Data/Citrix Repeater), my take is a little different: "Just because the Web site is messed up doesn't mean the users don't deserve decent performance."

The question was about no-cache, but let's shift over to max-age for a moment, where the hack I have in mind is less messy. Suppose the browser treated:

Cache-Control: max-age=0, immutable

as if it were:

Cache-Control: max-age=0, stale-while-revalidate=[1 year]

This would give all the user-visible performance of immutable because the stale resource is served from the cache and the revalidation is done after the fact.

Now, some of the value of "immutable" is to prevent the revalidations altogether, which this doesn't do. But I suspect that something can be done about this as well...

With no-cache, I'd want some reasonably strong tie-breaker before I paid any attention to immutable: no-cache + immutable + something else.

That's browser object-loading behavior, where shift-reload cures all ills. In a client-side app, I'd be more cautious. Of course, with a client-side app, I'd want things to work even if the response's Cache-Control header had been rewritten or dropped by an intervening proxy, so I'd ignore immutable, max-age, etc. except on objects I already thought of as highly cacheable.

Robert

annevk commented 7 years ago

@mayhemer @mcmanus thoughts?

mnot commented 7 years ago

FYI - CC: immutable has been adopted by the HTTP WG, and is being defined over at https://github.com/httpwg/http-extensions.

mayhemer commented 6 years ago

"no-cache" fetch mode is the same thing as reload (F5), Gecko code reference [1][2][3]. C-c: immutable was specifically crafted for this case - to not revalidate on plain F5. Hence, I agree with @wanderview that "no-cache" fetch mode should special-case immutable resources and not do revalidation at all for them. Immutable is an optimization. If it needs to be overruled, "reload" fetch mode can be used, but what for when the resource on the server is expected to be always the same as the one we have already cached before? In other words, for immutable resources the validation is expected to always pass, so it can be freely skipped.

Note that immutable is something web admins have to use with some level of caution. It does exactly what it says hence it has to be used only on resources that are actually not changing during their entire lifetime to not confuse users reloading their pages.

However, final word should come from @mcmanus, the father of cc: immutable.

[1] https://dxr.mozilla.org/mozilla-central/rev/0bb0f14672fdda31c19aea1ed829e050d693b9af/netwerk/protocol/http/HttpBaseChannel.cpp#2843 [2] https://dxr.mozilla.org/mozilla-central/rev/0bb0f14672fdda31c19aea1ed829e050d693b9af/netwerk/protocol/http/nsHttp.cpp#371 [3] https://dxr.mozilla.org/mozilla-central/rev/0bb0f14672fdda31c19aea1ed829e050d693b9af/docshell/base/nsDocShell.cpp#11788

annevk commented 6 years ago

FWIW, @mcmanus confirmed the above in email. Sounds like this will require changes then and corresponding test changes. Anyone up for making those?

wanderview commented 6 years ago

I'm sorry, what change is exactly being proposed and where was it decided we wanted to do that?

I haven't seen anything to change my view from https://github.com/whatwg/fetch/issues/308#issuecomment-243155311. If you set immutable at the server then you are opting in to validation always passing which means you must use no-store or reload to hit the server again.

annevk commented 6 years ago

Ah right, I guess at best we'd reference the immutable RFC for clarity.

mnot commented 4 years ago

See these tests; as far as I can tell, none of the three browser engines is acting in this way.

The failing test caches a response with:

Cache-Control: max-age=10000, immutable
ETag: "abcd"

then pauses three seconds and makes a request with no-cache in the fetch init; it's expected to come from cache.