15 ms·
Using Immutable Caching to Speed Up the Web
- nicolaslem 10y agoWhat is the difference between an immutable resource and setting the resource to expire in 10 years? Many websites already do that, they change the URL each time the content changes.
- kuschku 10y agoFirefox won’t reload the resource, even if the page the resource is on is POSTed to. Use case: Logging into Facebook, previously browsers reloaded all resources.
- 64bittechie 10y agoYou typically do a 302 redirect AFTER the POST authentication. This feels more of a publicity stunt more than anything. It might affect very few use-cases. Bulk of the requests on the web are GETs anyway.
- niftich 10y agoI agree. Facebook redirects a successful login POST with a 302, which then results in a GET to '/'. This is an extremely common pattern. Once you're making GETs, 'fresh' resources can be served from cache without revalidation [1]. This is basically the whole point of the fresh vs. stale distinction. [1] https://tools.ietf.org/html/rfc7234#section-1 https://tools.ietf.org/html/rfc7234#section-1
- nimrody 10y agoWhy would the browser need to reload all resources after a POST request? Presumably, only the main (HTML) page should be refreshed and other linked items (CSS/JS/media) with high max-age (and no 'must-revalidate' cache control header) should use the previously cached content.
- jjoe 10y agoThe difference is that in the case of immutable the browser does not send a 304 conditional.
- duskwuff 10y agoReally? The article implies that the whole point of Immutable is that the browser won't revalidate contents. (Also, "304" is an HTTP response code -- "Not Modified" -- not something the browser sends.)
- jjoe 10y agoMeant to say that there's no conditional with immutable. Corrected, thanks.
- duskwuff 10y agoI still don't think that's accurate. My experience is that a future Expires date -- even relatively near-future -- is sufficient to prevent an If-Modified-Since request. (Which is what I think you mean by "304 request".)
- jjoe 10y agoIt's up to the client to decide based on Last-Modified (if previously sent by the server) and its own implementation. But I guess browsers are going to be a tad bit aggressive especially if Last-Modified is absent. Hence the overly aggressive 304s.
- bzbarsky 10y agoFor normal loads, yes. The problem people are trying to solve here is that users hit the relaod button. A lot. And if you hit the reload button, that will send If-Modified-Since for everything on the page, no matter what Expires says, because the user intent is to ignore Expires headers. That's what the immutable thing is about: indicating that even in the reload scenario the Expires is authoritative and no If-Modified-Since request should be sent.
- Klathmon 10y agoI'm not sure if this is in-use anywhere, but it may lead to better "cache eviction" policies. Saying something is immutable has different implications than saying "I want it cached for 10 years". The former would allow a browser to apply some heuristics and say for example evict something from the cache when it hasn't been referenced on a page for the last 5 times you went there (the assumption being that it was changed and the new resource is taking over in it's place). That can lead to things being held in the cache for longer without having to use a straight "oldest evicted first" kind of method which can lead to thrashing if the cache size is too small or some resources are too big.
- jrochkind1 10y agoI'd imagine 'immutable' but not recently used things will still be evicted from the cache at some points, when space is needed. There's no reason for them not to be, is there? A browser can already apply different eviction policies to things with very long `expires`, I don't know if any do. I'm having trouble seeing what this adds practically, too. I guess it's more of a clear semantic intent to say 'immutable' when you need that, instead of 'expires a long time from now'. Practically though?
- jonknee 10y ago> Saying something is immutable has different implications than saying "I want it cached for 10 years". Only if you have a system that you keep for more than 10 years. If a browser dumps stuff that it was told it can keep for a decade that means it can also dump stuff that it was told will never change. If the cache is full of things that are immutable something still has to go.
- Klathmon 10y agoOh definitely, I meant more in the sense of being able to evict things more "intelligently". If stuff needs to go, it needs to go. It's going to happen. But if you have to choose between a file which was told to be cached for 10 years, and one which was labeled "immutable" but hasn't been referenced on the page it was previously for the last 10 loads, it might be a better choice to evict the immutable one.
- paulddraper 10y agoThe reality of most browsers is that they ignore the cache time in many cases, like refreshing, in order to work with broken pages. In a perfect world, we'd just be able to max-age and immutable would be redundant.
- magila 10y agoWhich raises the question: How long until browsers start ignoring the immutable header to work around broken pages?
- tyingq 10y agoThey say the difference goes back to this observation[1] from Facebook: "we've noticed that despite our nearly infinite expiration dates we see 10-20% of requests (depending on browser) for static resource being conditional revalidation. We believe this happens because UAs perform revalidation of requests if a user refreshes the page" It sounds like immutable is being introduced so that Firefox can leave the current behavior in place, and only instantiate the new behavior for "immutable" resources. This seems different than the chrome approach, where they plan on changing the behavior for all "unexpired" resources. [1]https://www.ietf.org/mail-archive/web/httpbisa/current/msg25463.html https://www.ietf.org/mail-archive/web/httpbisa/current/msg25...
- niftich 10y agoThey could just be seeing 10%-20% of the people doing a Ctrl+F5 'force refresh' -- after all, they're speculating, and have no real data on whether browser or user behavior is responsible for the numbers they're seeing.
- Tenoke 10y agoYou think they didn't test their assumption?
- niftich 10y agoI think they did, but there's not enough information available to reliably distinguish 'normal' reloads from 'force-reloads', unless they ran onKeyDown javascript and correlated the events after the fact. A comment from Facebook [1] on the Chrome bug says they started logging 'window.performance.navigation.type', which distinguishes between [2] normal navigation, reload, history traversal (back/forward), and undefined. [1] https://bugs.chromium.org/p/chromium/issues/detail?id=505048#c50 https://bugs.chromium.org/p/chromium/issues/detail?id=505048... [2] https://developer.mozilla.org/en-US/docs/Web/API/Navigation_timing_API https://developer.mozilla.org/en-US/docs/Web/API/Navigation_...
- tyingq 10y agoFirefox themselves appear to have tested and confirmed that regular F5/Refresh (not Ctrl+F5) causes revalidation: http://bitsup.blogspot.de/2016/05/cache-control-immutable.html http://bitsup.blogspot.de/2016/05/cache-control-immutable.ht...
- mbell 10y agoThe 'reload' action in browsers has a different meaning than most people expect and does not do the same thing as highlighting the url and hitting enter, or pasting the url into a new tab. 'reload' forces all assets to be re-validated, regardless of the freshness of the cache. The `immutable` header allows browsers to skip this revalidation.
- deleted 10y ago[deleted]
- roddux 10y agoThis is related to the Chrome caching update; as discussed here: https://news.ycombinator.com/item?id=13492483 https://news.ycombinator.com/item?id=13492483 Two wholly different strategies, which has ultimately split how the browsers handle caching.
- mnarayan01 10y agoI wonder if this will bring back the "hard refresh".
- cpeterso 10y agoI'm curious, too. The blog post says refreshing the page won't revalidate the immutable resources, but doesn't say what happens for a CTRL+SHIFT+R hard refresh. The Firefox bug mention hard refresh, but don't say what was implemented: https://bugzilla.mozilla.org/show_bug.cgi?id=1267474 https://bugzilla.mozilla.org/show_bug.cgi?id=1267474
- cpeterso 10y agoPatrick McManus, the Firefox developer of this feature, confirmed that hard reload will load immutable resources from scratch, so the user always has a nuclear option for fixing cache corruption. :)
- deno 10y agoYou can just disable caching altogether in Dev Tools. Extra refresh levels are unnecessary.
- deleted 10y ago[deleted]
- jjoe 10y agoWith WiFi hotspots dropping connections more often than not, how many people would know they need to CTRL-F5 to "fix" a broken page/image/JS/CSS? I just hope the draft as-is expires and never makes it to an RFC.
- minitech 10y agoWhy would a browser cache an incomplete response? Content-Length exists, and failing that, there are chunked transfers.
- jjoe 10y agoContent-Length MUST be ignored in some cases (encoding). Not all send a Content-Length header (it's a SHOULD not a MUST).
- minitech 10y agoIf you don’t tell the browser in some way where your response ends (with Content-Length, chunked, or HTTP/2 [?]), you can’t reuse connections, as far as I know. If that’s the case, you probably don’t care enough about performance to use `immutable` anyway.
- jjoe 10y agoJust playing devil's advocate there for a minute. And this is definitely one of those things I've had to work around.
- twoodfin 10y agoCould you clarify your objection? Presumably clients would never immutably cache a resource they couldn't validate.
- jjoe 10y agoHow does validation work in the case of a 200 status and no Content-Length header?
- zokier 10y agoI'd be very wary of using any HTTP headers with permanent effects. They seem like a way to get easily burned by accident. For immutable caching in particular, I'd probably try to utilize some variation of content-based addressing, eg having the url have the hash of the content. See also: http://jacquesmattheij.com/301-redirects-a-dangerous-one-way-street http://jacquesmattheij.com/301-redirects-a-dangerous-one-way... and the related HN thread with good discussion
- mmastrac 10y agoIt's not permanent if you don't make it permanent - like the other cache-control headers, you can specify the amount of time that a resource is considered immutable. All this does is change the time period in which the browser avoids sending 304s.
- Confiks 10y agoThis might be considered similar to the DoS vector that was also present in the HTTP Public Key Pinning proposal [1]; an adversary seizing temporary control over the server can convince clients to not request a response from the server for a certain period, or in the case of HPKP request a response that cannot possibly be fulfilled. Its seems much more mundane in this Cache-Control case, but it is the same vector nevertheless. [1] https://blog.qualys.com/ssllabs/2016/09/06/is-http-public-key-pinning-dead https://blog.qualys.com/ssllabs/2016/09/06/is-http-public-ke...
- mtberatwork 10y agoYou can get burned using 301 redirects over 302 just as easily if you are not careful. But it does not mean that we should abandon using 301 redirects.
- jerf 10y agoThat's exactly what Facebook is doing: https://code.facebook.com/posts/557147474482256/this-browser-tweak-saved-60-of-requests-to-facebook https://code.facebook.com/posts/557147474482256/this-browser... But I agree that you are correct to issue this warning. It is something you need to understand before you accidentally slather that on all your content.
- btilly 10y agoWhat I really want is the exact opposite. I'd like to see a flush-before header to have a particular web page NOT pull older static resources. The reason is simple. Websites have lots of static content that seldom changes. But you don't know in advance when it is going to change. However after the fact you know that it did. So you either set long expiry times and deal with weird behavior and obscure bugs after a website update, or set short ones and generate extra load and slowness for yourself. Instead I'd like to have the main request send information that it does not want static resources older than a certain age. That header can be set on the server to the last time you did a code release, and a wide variety of problems involving new code and stale JS, CSS, etc go away.
- hansjorg 10y agoThat sounds convenient, but using versioned URLs will already give you that. Except for when you bump the version without changing the resource I guess.
- romaniv 10y agoThat is true in most cases, but versioned URLs are a hack that requires you to change document's address and then change a bunch of other documents just to fix an issue with HTTP. It's like changing file content and their names to fix something in FTP protocol. Also, it doesn't cover all the cases properly, because the page with versioned URLs can be cached as well.
- nemothekid 10y ago>Also, it doesn't cover all the cases properly, because the page with versioned URLs can be cached as well. If even the page with the versioned URL is cached, what good would a "Flush-Before" header do you?
- reggieband 10y agoVersioned URLs have a couple of drawbacks. If I have asset.v0.js, asset.v1.js, asset.v2.js then I am exposing some useful information in the sequence of filenames. It is also a bit harder to keep track of versions across systems. With hashes, you don't need to know what the last version number was - just what the hash of the current file is. If you have multiple build machines building multiple branches, keeping versions in-line is thing unto itself. I've had problems with versioning in the past where careless merges caused issues - that doesn't happen with hashes. The main drawback with hashed asset names is it can be a bit more tricky to determine what assets are currently in use and which can be safely deleted.
- nachtigall 10y agoThe last image about Squid proxy is included too small in the post, here it is in a readable way: https://hacks.mozilla.org/files/2016/12/sq.png https://hacks.mozilla.org/files/2016/12/sq.png
- romaniv 10y agoHTTP caching is a mess. I wonder why no one proposed a properly redesigned and negotiable protocol that covers all the edge cases. (And maybe supports partial caching/partial re-validation of pages.)
- bhldr 10y agoOn my phone, so unfortunately no reference, but there is a HTTP 2 spec underway that allows a client to send a cache manifest frame. A server can then push the resources that are newer. Pretty much exactly what's needed.
- romaniv 10y agoUnless we're talking about different things, cache manifest is an HTML 5 feature designed to enable websites to work offline. That's quite different from HTTP-level caching, which would be applicable to any files/resources and designed primarily with performance and bandwidth savings in mind. I might be unaware of some relevant HTTP 2 features, though.
- pornel 10y agoThe current HTTP RFC is actually quite nice: http://httpwg.org/specs/rfc7234.html http://httpwg.org/specs/rfc7234.html
- mixedbit 10y agoI just realized that until http is completely replaced with https, private mode should be always used to browse the Internet on a not trusted wifi network. Otherwise malicious content injected on such a network can be cached and reused by the browser forever.
- NoGravitas 10y agoTrue, but you should also: 1. Use HTTPS Everywhere. 2. Never use an untrusted WiFi network without a VPN.
- re 10y ago> In Firefox, immutable is only honored on https:// https:// transactions. https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Ca... > Clients should ignore immutable for resources that are not part of a secure context https://tools.ietf.org/html/draft-mcmanus-immutable-00 https://tools.ietf.org/html/draft-mcmanus-immutable-00
- georgeaf99 10y agoThe concept of immutable assets and links is at the core of IPFS, a distributed alternative to HTTP. Since Firefox inplements the concept of immutable assets now, it would be totally reasonable to load these assets in the browser peer to peer (see WebRTC and webtorrent). I think this would be a great way to retrofit some decentralization into webpages!
- lclarkmichalek 10y agoI'm not sure it would be reasonable. To do that without deanonymising people would be an awful lot of work, and at the end if it lead to faster results, that would seem to be ripe for timing attacks to I.e. Figure out if anyone is browsing stonewall.org on your LAN
- ianopolous 10y agoOpenBazaar are using IPFS over a Tor transport. You could have a fast lane direct from the (http) server, then a slow P2P lane over Tor, both using the same content addressed protocol, and caching the results locally for instant reloads.
- deleted 10y ago[deleted]
- niftich 10y agoWhat a mess, but perhaps a happy ending. I made two other comments prior to this one in this thread, but then I read the Bugzilla thread [1] opened by Facebook that laid out the issue and Mozilla's defense. It's a highly enlightening read; I can't recommend it enough. To summarize, the issue is that Facebook was seeing a higher rate of cache validation requests than they'd expect, and looked into it. Chrome produced an updated chart documenting different refresh behaviors [2], which is the spiritual successor of this now-outdated stackoverflow answer from 2010 [3], and in response to Facebook's requests, and have re-evaluated some of their refresh logic. In this thread, Firefox was being asked to do the same, but they pushed back on adding yet another heuristic and in turn proposed a cache-control extension. Meanwhile, Facebook proposed the same thing on the IETF httpbis list, where the response not enthusiastic [4], largely feeling that that this is metadata about the content and not a prescriptive cache behavior, and that the HTTP spec already accounted for freshness with age. One of Mark Nottingham's responses [5]: (...) From time to time, we've had people ask for "Cache-Control: Infinity-I-really-will-never-change-this." I suspect that often they don't understand how caches work, and that assigning a one-year lifetime is more than adequate for this purpose, but nevertheless, we could define that so that it worked and gave you the semantics you want too. To keep it backwards compatible, you'd need something like: Cache-Control: max-age=31536000, static (or whatever we call it) [1] https://bugzilla.mozilla.org/show_bug.cgi?id=1267474 https://bugzilla.mozilla.org/show_bug.cgi?id=1267474 [2] https://docs.google.com/document/d/1vwx8WiUASKyC2I-j2smNhaJaQQhcWREh7PC3HiIAQCo/edit https://docs.google.com/document/d/1vwx8WiUASKyC2I-j2smNhaJa... [3] http://stackoverflow.com/questions/385367/what-requests-do-browsers-f5-and-ctrl-f5-refreshes-generate http://stackoverflow.com/questions/385367/what-requests-do-b... [4] https://www.ietf.org/mail-archive/web/httpbisa/current/msg25463.html https://www.ietf.org/mail-archive/web/httpbisa/current/msg25... [5] https://www.ietf.org/mail-archive/web/httpbisa/current/msg25505.html https://www.ietf.org/mail-archive/web/httpbisa/current/msg25...
- achairapart 10y agoMaybe it's time for browsers to go beyond the cache concept and implement a common standard package manager. Download once, stay forever. True immutable. As developers, we try everyday to squeeze till the last byte and optimize things. We all know how performance is important. So why download for every website the same asset: React, jQuery, libraries, CSS utils, you-name-it? What a waste!
- notatoad 10y agoHow is your proposal different to what's happening here? If two websites call a library from the same CDN that implements immutable, then isn't that just a distributed package manager with URL-based namespacing?
- achairapart 10y agoThe problem will be that every website should use the same CDN. Not likely to happen and centralize things is never good. You'll also miss other features: version range alone could save tons of bandwidth.
- notatoad 10y ago>centralize things is never good. but centralizing in the browser is?
- vvggff 10y agoYeah, you know it so much that I have to download 100s of MBs to view a text-only site.
- achairapart 10y agoWhy that? The browser download only the assets you require.
- Orangeair 10y agoShouldn't using common CDNs solve this problem?
- whack 10y agoSorry if this is a dumb question. How is immutable caching any different from cache-control headers with a max age of 100 years?
- discreditable 10y agoWhen you click refresh, your browser will revalidate those 100yr lifespan resources. If they are immutable, it won't revalidate.
- whack 10y agoAccording to this link, the browser won't perform any revalidation for the duration of the max-age? https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching#max-age https://developers.google.com/web/fundamentals/performance/o... However, what if you want to update or invalidate a cached response? For example, suppose you've told your visitors to cache a CSS stylesheet for up to 24 hours (max-age=86400), but your designer has just committed an update that you'd like to make available to all users. How do you notify all the visitors who have what is now a "stale" cached copy of your CSS to update their caches? You can't, at least not without changing the URL of the resource. After the browser caches the response, the cached version is used until it's no longer fresh, as determined by max-age or expires, or until it is evicted from cache for some other reason— for example, the user clearing their browser cache. As a result, different users might end up using different versions of the file when the page is constructed: users who just fetched the resource use the new version, while users who cached an earlier (but still valid) copy use an older version of its response.
- tempestn 10y agoThat's all true, but it applies to regular page loads, not the case where the user explicitly presses the reload button.
- fastest963 10y agoIt shouldn't revalidate unless there are other headers that might cause it to revalidate (If-Modified-Since?).
- Animats 10y agoThis should be done using subresource integrity. Then, you know it hasn't changed. There should be some convention for encoding the hash into the URL, so that any later change to an "immutable" resource will be detected. With subresource integrity hashes, you don't have to encrypt public content. Less time wasted in TLS handshakes.
- grizzles 10y agoAs an engineer, I've always resented the unnecessary time I spend waiting for data in web browsers, so the bad state of caching in web browsers is an issue that's been on my mind for a long time. There are a few ways to improve things: 1. Predictive modelling user resource demand in the browser (eg. preloading data) Very very easy to do nowadays with great accuracy. 2. Better cache control / eviction algorithms to keep the cache ultra hot. 3. (This). Immutable caching is one of the major ways we could improve things. I'm not a fan of the parent articles' way of doing it though, because if widely implemented it will break the web in subtle ways, especially for small companies and people that don't have Facebooks resources and engineering talent. It doesn't take into account usability issues and therefore leaves too much room for user error. I've written up a very simple 11 line spec here that addresses this issue. https://gist.github.com/ericbets/5c1569856c2ad050771ec0c866f531f3 https://gist.github.com/ericbets/5c1569856c2ad050771ec0c866f... I'll throw out a challenge to HN. If someone here knows chromium internals well enough to expose the cache and assetloader to electron, within a few months I'll release an open source ML powered browser that speeds up their web browsing experience by something between 10X-100X. Because I feel like this should have been part of the web 10 years ago.
- PetahNZ 10y agoSo much for useful file names. What if I wanted to download this? What about SEO?
- grizzles 10y agoThanks for your feedback. What do you think about this (filename preserving) scheme: example.org/urlcache/path/to/file/file.mimext?hashalg=hash eg. example.org/urlcache/file.png?sha384=9b78b27b73668784e38c8a58a8535deaaecb77709
- jogjayr 10y agoA lot of webapps already use this type of scheme for cache-busting, though of course the hash algorithm isn't mentioned. I assume that's important so that the browser can do verification?
- stockkid 10y ago> The page’s javascript, fonts, and stylesheets do not change between reloads So is this like Rails' Turbolink but built into the browser?
- kingkool68 10y agoWhat's the difference between Cache-Control: Immutable and setting expires headers really far in to the future?
- imaginenore 10y agoWhen you do a hard refresh (Ctrl + F5 / Apple + R), your cache gets invalidated. The immutable parts don't need to be reloaded, because they are immutable.
- cakoose 10y agoOh, interesting. Is that the only difference? How often people actually do a hard refresh? I would guess most people don't know about that key combination.
- arnorhs 10y agonot only that, but even when you have a resource with a long cache time, and cache-control public, the browser will still do a request for the file headers (a conditional request - one that serves the content if it has changed/doesn't match what the browser expects) so an immutable resource wouldn't even need that request
- spectrum1234 10y agoWow I'm out of touch with front end dev. Someone please explain to me why this hasn't been standard already.
- z3t4 10y agoHow do you update the URL and everywhere its used once an asset (image or script) is changed ? Automatic script or manually ?
- Udo 10y agoWhat happens if the immutable file is borked in transfer, leading to a partial file sitting in cache? Will this lead to a new class of problem that can only be solved by nuking the entire browser cache? It seems to me the way to do this right would have included a checksum of the content.
- danarmak 10y agoA hard refresh (Ctrl+F5) of the page will refresh immutable resources too, so you won't need to clear the whole browser cache.
- anon1253 10y agoWe should really try to integrate something like https://ipfs.io/ https://ipfs.io/ in browsers
- deleted 10y ago[deleted]
- deleted 10y ago[deleted]
- hpagey 10y agoFrom what I understand, the browsers don't really adhere to far-future expiry headers when the user manually reloads a page, instead they re-request every resource to see if it's really not expired. For resources that the server flags as immutable (upon first request), the browser won't make further requests, but instead instantly reloads the elements out of its local cache.
- EdSharkey 10y agoA very creditable action, cheers to Mozilla! This increases the democratization of the web and allows small fries to have a disproportionately larger footprint.