My goal is to cache images in browser's cache.
Cache-Control: public, max-age=10368000
header is attached to the requested image to cache the image.
Furthermore, ETag: f5f9f1fb39790a06c5b93735ac6e2397
header is attached too to check if image has changed once max-age
is reached.
When the same image is requested again, if-none-match
header's value is checked to see if image has changed. If it has not, 304
is returned.
I am using Fiddler to inspect http traffic (note - behaviour described below was happening already before Fiddler, so it is not the problem)
Chrome version - 77.0.3865.90 (Official Build) (64-bit)
I expect that the image would get cached 10368000 seconds. Unless 10368000 seconds have passed, image gets served from browser's cache on each request. Once 10368000 seconds have passed, request is made to the server which checks Etag. If the image has not changed on the server, return 304 to the client and extend caching period to another 10368000 seconds.
Fiddler tells that an image was requested and served
Furthermore, the fact that the image is cached is seen in ~/Library/Caches/Google/Chrome
as it appears there.
Fiddler tells that image was served from the cache
Why did Chrome make an additional request for the image and served it from the cache only after it received 304 response?
I see that when requesting the image second time Cache-Control: max-age=0
request header is set. As I understand, it means that Chrome wants to re-validate if cached image is valid before serving it. But why?
Some people online have told that Etag
header is the reason for Chrome making sure images are valid. Even if I do not include Etag
header, just have Cache-Control: public, max-age=10368000
in the first response, the Cache-Control: max-age=0
exists in second request's headers.
I have also tried excluding public, making it private etc. I also added Expires
and Last-Modified
pair with and without max-age=10368000
and get the same behaviour.
Furthermore, in dev tools I have NOT checked Disable cache. So the cache is enabled for sure which also makes sense because the image was served after returning 304.
This exact behaviour happens also when, instead of clicking link bar and pressing Enter, I press Refresh arrow aka CMD + R. If I do hard refresh CMD + SHIFT + R, then the image is requested as if it is first time requesting it, which makes sense.
Firefox works exactly as expected.
Fiddler tells that an image was requested and served
Furthermore, if I hover over response status, then it says OK
BUT Firefox shows that it was cached.
FURTHERMORE, Fiddler detected no activity on the second request, so the image was served from Firefox's cache. Unlike Chrome, which made another request to the server just to receive 304 from it.
Thank you very much for your time and help. I highly appreciate it and am open to provide any other information. Really looking forward to what you think about this.
Have a nice day :)
Why did Chrome make an additional request for the image and served it from the cache only after it received 304 response?
Because you told it to - whether you realise it or not! When you browse forwards and backwards the cached image will be used. When you click refresh or F5 (Cmd R on MacOS) or a page, you are explicitly asking Chrome to double check if the page is still the correct one. So when you click on the URL bar and click enter it’s the same thing. Chrome thinks that the only reason you’d do that, on a URL you are already on, you must want it to check.
I see that when requesting the image second time Cache-Control: max-age=0 request header is set. As I understand, it means that Chrome wants to re-validate if cached image is valid before serving it. But why?
Correct. See the answer to this question. As to why - because as per above you have Chrome a signal you wanted to refresh.
There is also the cache-control immutable header, which is designed to tell the browser never to re-fetch if in the cache - even on refresh.
Firefox works exactly as expected.
Interesting. I actually like the way Chrome does this. Certainly for reload (F5/Cmd + R). Appreciate it confused you (though hopefully will be less confusing now you understand it), but testing this is not the norm, and most people don’t click the URL bar and then hit enter without changing the URL unless they want to recheck the current page with the server.