44

I have Amazon S3 objects, and for each object, I have set

Cache-Control: public, max-age=3600000

That is roughly 41 days.

And I have Amazon CloudFront Distribution set with Minimum TTL also with 3600000.

This is the first request after clearing cache.

GET /1.0.8/web-atoms.js HTTP/1.1
Host: d3bhjcyci8s9i2.cloudfront.net
Connection: keep-alive
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
User-Agent: Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.57 Safari/537.36
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8

And Response is

HTTP/1.1 200 OK
Content-Type: application/x-javascript
Content-Length: 226802
Connection: keep-alive
Date: Wed, 28 Aug 2013 10:37:38 GMT
Cache-Control: public, max-age=3600000
Last-Modified: Wed, 28 Aug 2013 10:36:42 GMT
ETag: "124752e0d85461a16e76fbdef2e84fb9"
Accept-Ranges: bytes
Server: AmazonS3
Age: 342557
Via: 1.0 6eb330235ca3971f6142a5f789cbc988.cloudfront.net (CloudFront)
X-Cache: Hit from cloudfront
X-Amz-Cf-Id: 92Q2uDA4KizhPk4TludKpwP6Q6uEaKRV0ls9P_TIr11c8GQpTuSfhw==

Even while Amazon clearly sends Cache-Control, Chrome still makes second request instead of reading it from Cache.

GET /1.0.8/web-atoms.js HTTP/1.1
Host: d3bhjcyci8s9i2.cloudfront.net
Connection: keep-alive
Cache-Control: max-age=0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
User-Agent: Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.57 Safari/537.36
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
If-None-Match: "124752e0d85461a16e76fbdef2e84fb9"
If-Modified-Since: Wed, 28 Aug 2013 10:36:42 GMT

Question: Why does chrome makes second request?

Expires This behavior changes when I put an explicit Expires attribute in headers. Browser will not send subsequent request for Expires header, but for cache-control public, it does send it. My all S3 objects will never change, they are immutable, when we change file, we put them as new object with new URL.

In Page Script Reference Chrome makes subsequent requests only sometimes, I did this test by actually typing URL in browser. When script is referenced by HTML page, for few subsequent requests chrome loads cached scripts, but once again after sometime, once in a while it does send request to server. There is no Disk Size issue here, Chrome has sufficient cache space.

Problem is we get charged for every request, and I want S3 objects to be cached forever, and should be loaded from Cache and should never connect to server back.

Akash Kava
  • 39,066
  • 20
  • 121
  • 167

5 Answers5

47

When you press F5 in Chrome, it will always send requests to the server. These will be made with the Cache-Control:max-age=0 header. The server will usually respond with a 304 (Not Changed) status code.

When you press Ctrl+F5 or Shift+F5, the same requests are performed, but with the Cache-Control:no-cache header, thus forcing the server to send an uncached version, usually with a 200 (OK) status code.

If you want to make sure that you're utilizing the local browser cache, simply press Enter in the address bar.

Oliver Salzburg
  • 21,652
  • 20
  • 93
  • 138
  • Simple and effective answer. TIL `F5` and `Enter` make different requests. – Gras Double Mar 01 '17 at 21:38
  • 1
    Three days hitting my head with this. THANKS! I was presing Ctrl + F5 and didn't know where Control:no-cache came from and why the browser was ignoring my Cache-Control, or if I was doing something wrong. God, thanks! And @GrasDouble, thx for the link. I know the comments should not be used to thanks, but finding you answer was a great relief. – Alfonso Nishikawa Feb 13 '18 at 17:25
  • 1
    Great answer, I didn't check the request headers, you can run `fetch` to check if it's really getting from disk ex: `fetch('YOUR_URL')` – Victor Castro Mar 01 '18 at 14:19
  • Is there any way by which I can avoid sending the request to server in case of F5? As of now it sends the request to server, then server responds back with 304 and then it gets loaded from cache. I want browser to load it from cache directly when someone press F5, as my resources are available in disk cache. – Debajit Majumder Apr 26 '18 at 06:46
  • @DebajitMajumder Then you need to allow the client to do that. Usually with an `Expires` header. – Oliver Salzburg Apr 26 '18 at 09:20
  • With `Shift+F5`, there's also no `if-none-match` header in the request. – maaartinus May 18 '18 at 22:01
  • This save the day. Any official links explaining this behavior? – Joy George Kunjikkuru May 10 '19 at 15:59
  • @JoyGeorgeKunjikkuru Sorry, no. It's just what I observed when I researched it. – Oliver Salzburg May 10 '19 at 17:56
  • Based on my tests, press ENTER in the address bar: Firefox (111.0.1) reuses the cached value in the local browser. Chrome (111.0.5563.146) doesn't reuse the cached value but it fires an additional request to the server. – Bằng Apr 02 '23 at 18:53
24

If the HTTP Response contains the etag entry, the conditional request will always be made. ETag is a cache validator tag. The client will always send the etag to the server to see if the element has been modified.

woolagaroo
  • 1,542
  • 2
  • 22
  • 31
  • 1
    Thanks, but that is wrong design, shouldn't it ignore ETag while Max Age & public cache is specified. S3 automatically adds ETag, do I have to remove it or can I change headers to support expected behaviour? I don't know if there is way to remove ETag in S3. – Akash Kava Oct 23 '13 at 08:29
  • On Chrome I have found that removing the entry is the only way to impede a conditional http request. IE does a much better job at this IMHO. – woolagaroo Oct 23 '13 at 09:00
  • So is it a bug in Chrome, or is it correct according to HTTP 1.1 protocol? – Akash Kava Oct 23 '13 at 09:35
  • When I had the issue I did not find any metions on the RFC of the http 1.1 Protocol on which one should take precedence, or if the two entries could be combined. I did find some other answers (not officials) http://vadmyst.blogspot.co.at/2005/09/server-side-etag-vs-cache-control-max.html http://stackoverflow.com/questions/6350384/http-combining-expiration-and-validation-caching Both answers indicate that it is a bug in Chrome – woolagaroo Oct 23 '13 at 11:06
  • 2
    If there's an http **response** then the request already took place and the `max-age` was ignored. – Pablo Fernandez Jun 10 '14 at 21:41
  • 39
    In my testing, Etags don't come into play (all my resources have an etag). I'm pretty sure this is how you're testing with Chrome. Pressing "enter" on the address bar is best way to test cache. F5 or clicking reload with send the "max-age=0" header. See also: http://stackoverflow.com/a/16510707/789658 – Costa Jul 03 '14 at 02:23
  • It worked correctly for me. I suspect that if it was an issue in Oct 2013, it was fixed since. – Alexis Wilke Sep 20 '15 at 03:47
  • 3
    As of this date, Costa's reply is still relevant: Chrome sends a max-age=0 in the request header if you refresh the page. If you press enter in the URL, it doesn't. – DarkNeuron May 09 '16 at 12:34
  • Yes, that's correct. If you refresh the page then it gives 304 http code and goes to server while if you hit the url again it would be fetched from cache with 200 http status code. – Piyush Beli Feb 22 '17 at 10:01
  • 6
    In Chrome Version 57.0.2987.133 (64-bit), hitting enter on the URL still seems to be sending a conditional request and max-age=0 in the request even though the response from cloud front has Cache-Control:max-age=300. Basically, I can't seem to get it to ever fetch from the browser's cache regardless of how I issue the request. I've verified the the browser cache is not disabled in Dev Tools. Any ideas? This is an image. I'm wondering if the Content-Type has anything to do with it. – Bradley Apr 08 '17 at 01:20
  • 5
    2 things: 1. When going to URL for my image in CloudFront directly in Chrome tab, the only way I can get it to reliably pull from browser cache is to get to the URL via Back/Forward. If I F5 or hit Enter in URL, I always see conditional request with 304. 2. Only appears to be the case when going directly to image URL. When used in content of an HTML document, the caching works as described above where an F5 refresh and hitting Enter in the URL yield different results. Can only assume Chrome is treating navigating directly to URL as a sign it should do a conditional request. Expected? – Bradley Apr 08 '17 at 01:40
  • 2
    @Bradley comment still holds true, saved me so much time! F5 or directly loading a resource from URL navigator, chrome sends Cache-Control: max-age=0. While when asking for the resource in the app, the resource is served from cache. – Ashwin Aggarwal Dec 03 '18 at 12:28
10

If Chrome Developer Tools are open (F12), Chrome usually disables caching.

It is controllable in the Developer Tools settings - the Gear icon to the right of the dev-tools top bar.

user3841754
  • 279
  • 3
  • 3
  • 6
    F12 only disables caching when you tick the box to disable it, when I am testing caching I am certain that caching is enabled. – Akash Kava Jul 17 '14 at 06:29
  • 1
    Great answer. I made the relevant changes in the server and was inspecting the results with Dev Tools (F12) open and could not see the impact. There is so much little things to know. +1 from me. – Soumya Kanti Dec 12 '16 at 10:31
  • 1
    OMG! I didn't realize that! Developer Tools "Disable cache" was checked in my browser - Doh! – Volksman Jan 14 '17 at 11:37
2

Chrome adds Cache-control: max-age=0 header when you use self-signed certificate. Switching from HTTPS to HTTP will remove this header.

Firefox doesn't add this header.

  • I ran into a very similar issue when testing response caching on `localhost` with Chrome—though, instead of sending `max-age=0`, it was sending `nocache`. Same result, of course. Regardless, it was clear that it _was_ sending this with each request, but it wasn't obvious _why_. This is useful to know when testing caching on a local development server, which will almost certainly be using a self-signed certificate. – Jeremy Caney Dec 16 '21 at 23:54
1

If you are hitting the refresh button for loading the particular page or resource, the if-modified-since header request is sent everytime, if you instead request the page/resource as a separate request in a new tab or via a link in a script or html page, it will load the page/resource from the browser cache itself.

This is what has happened in my case, may be this is the general universal case. I am not completely sure, but this is what I gathered via my digging.

Anirban Roy Das
  • 262
  • 4
  • 14
  • On opening the same request in a new tab, Chrome loads the response from the browser cache instead of firing an additional request. Thanks for sharing this information. – Bằng Apr 02 '23 at 18:56