62

Background:

  • IIS 7
  • AspNet 3.5 web app

Chrome dev tools lists 98 requests for the home page of the web app (aspx + js + css + images). In following requests, status code is 200 for css/images files. No cache info, browser asks server each time if file has to be updated. OK.

In IIS 7 I set HTTP header for cache control, set to 6 hours for the "ressources" folder. In Chrome, using dev tools, I can see that header is well set in response:

Cache-Control: max-age=21600

But I still get 98 requests... I thought that browser should not request one ressource if its expiration date is not reached, and I was expecting the number of requests to drop...

Robert Moore
  • 2,207
  • 4
  • 22
  • 41
Francois
  • 10,730
  • 7
  • 47
  • 80
  • I'm having a similar problem. Chrome seems to completely ignore the caching headers. – Alex D Nov 21 '12 at 12:54
  • I was using a max-age of 10 seconds for testing purposes and *nothing* ever worked, however if I do 30 seconds then everything works as expected. Chrome seems to have a minimum cache time, below which it gets ignored. – user3338098 Jan 27 '16 at 20:02

8 Answers8

117

I got it. Google Chrome ignores the Cache-Control or Expires header if you make a request immediately after another request to the same URI in the same tab (by clicking the refresh button, pressing the F5 key or pressing Command + R). It probably has an algorithm to guess what does the user really want to do.

A way to test the Cache-Control header is to return an HTML document with a link to itself. When clicking the link, Chrome serves the document from the cache. E.g., name the following document self.html:

<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>Test Page</title>
</head>
<body>
    <p>
        <a href="self.html">Link to the same page.</a>
        If correctly cached, a request should not be made
        when clicking the link.
    </p>
</body>
</html>

Another option is to copy the URL and paste it in the same tab or another tab.

UPDATE: On a Chrome post published on January 26, 2017, it is described what was the previous behavior and how it is changing by doing only revalidation of the main resource, but not of the sub-resources:

Users typically reload either because a page is broken or the content seems stale. The existing reload behavior usually solves broken pages, but stale content is inefficiently addressed by a regular reload, especially on mobile. This feature was originally designed in times when broken pages were quite common, so it was reasonable to address both use cases at once. However, this original concern has now become far less relevant as the quality of web pages has increased. To improve the stale content use case, Chrome now has a simplified reload behavior to only validate the main resource and continue with a regular page load. This new behavior maximizes the reuse of cached resources and results in lower latency, power consumption, and data usage.

In a Facebook post also published on January 26, 2017, it is mentioned that they found a piece of code were Chrome invalidates all cached resources after a POST request:

we found that Chrome would revalidate all resources on pages that were loaded from making a POST request. The Chrome team told us the rationale for this was that POST requests tend to be pages that make a change — like making a purchase or sending an email — and that the user would want to have the most up-to-date page.

It seems this is not the case anymore.

Finally, it is described that Firefox is introducing Cache-Control: immutable to completely stop revalidation of resources:

Firefox implemented a proposal from one of our engineers to add a new cache-control header for some resources in order to tell the browser that this resource should never be revalidated. The idea behind this header is that it's an extra promise from the developer to the browser that this resource will never change during its max-age lifetime. Firefox chose to implement this directive in the form of a cache-control: immutable header.

starball
  • 20,030
  • 7
  • 43
  • 238
kiewic
  • 15,852
  • 13
  • 78
  • 101
  • 1
    Isn't that the purpose of caching? – Pablo Fernandez Jun 10 '14 at 21:37
  • 14
    An easier way to test would be to copy your URL into a new tab :) – Fabio Beltramini Mar 03 '15 at 17:05
  • Chrome only loads from cache while in incognito mode, but not the other, which is extremely weird! – WoLfPwNeR Nov 30 '15 at 20:21
  • 1
    `F5` or `Ctrl-R` is a Reload command which asks the browser to reset the caches... It's not specific to Chrome. Also, a `Cache-Control: no-cache` header is sent to the server if the server wanted to take that in account... (it is important for proxies that could cache your page.) – Alexis Wilke Mar 28 '16 at 01:07
  • 6
    @AlexisWilke F5 should not clear caches, on Win/Linux you must press F5+Ctrl to refresh page + clear caches (see: https://en.wikipedia.org/wiki/Wikipedia:Bypass_your_cache) – csharpfolk Nov 01 '16 at 15:10
  • I am using meta tags for my cache instruction, chrome still ignores them, but Microsoft edge and Microsoft edge beta obeys the cache. I have had this header for a while now – amaugo somto May 08 '20 at 10:06
23

Chrome appears to be ignoring your Cache-Control settings if you're reloading in the same tab. If you copy the URL to a new tab and load it there, Chrome will respect the cache control tags and reuse the contents from the cache.

As an example I had this Ruby Sinatra app:

#!/usr/bin/env ruby

require 'sinatra'

before do
  content_type :txt
end

get '/' do
  headers "Cache-Control" => "public, must-revalidate, max-age=3600",
          "Expires" => Time.at(Time.now.to_i + (60 * 60)).to_s
  "This page rendered at #{Time.now}."
end

When I continuously reloaded it in the same Chrome tab it would display the new time.

This page rendered at 2014-10-08 13:36:46 -0400.
This page rendered at 2014-10-08 13:36:48 -0400.

The headers looked like this:

< HTTP/1.1 200 OK
< Content-Type: text/plain;charset=utf-8
< Cache-Control: public, must-revalidate, max-age=3600
< Expires: 2014-10-08 13:36:46 -0400
< Content-Length: 48
< X-Content-Type-Options: nosniff
< Connection: keep-alive
* Server thin is not blacklisted
< Server: thin

However accessing the same URL, http://localhost:4567/ from multiple new tabs would recycle the previous result from the cache.

slm
  • 15,396
  • 12
  • 109
  • 124
  • 2
    That is just the answer I needed. Fought with Chrome for an hour trying to work out the right combination of Cache headers then, finally found this post and bam, no need to worry. – Reid Johnson Oct 22 '14 at 18:15
  • 1
    Found the same thing. Hitting refresh or hitting 'enter' in the address bar would cause Chrome to ignore cache. Accessing the URL from a new tab would honour the cache. – Josh Weston Dec 08 '19 at 16:06
  • I am using meta tags for my cache instruction, chrome still ignores them, but Microsoft edge and Microsoft edge beta obeys the cache. I have had this header for a while now – amaugo somto May 08 '20 at 10:06
22

After doing some tests with Cache-Control:max-age=xxx:

  • Pressing reload button: header ignored
  • Entering same url any tab (current or not): honored
  • Using JS (window.location.reload()): ignored
  • Using Developer Tools (with Disable cache unselected) or incognito doesn't affect

So, the best option while developing is put the cursor in the omnibox and press enter instead of refresh button.

Note: a right button click on refresh icon will show refresh options (Normal, Hard, Empty Cache). Incredibly, no one of these affect on these headers.

sinuhepop
  • 20,010
  • 17
  • 72
  • 107
15

While this question is old, I wanted to add that if you are developing using a self-signed certificate over https and there is an issue with the certificate then google will not cache the response no matter what cache headers you use.

This is noted in this bug report: https://bugs.chromium.org/p/chromium/issues/detail?id=110649

Beyerz
  • 787
  • 2
  • 9
  • 20
  • 2
    This drove me crazy...twice! Thank you! Once I figured out this was the issue, I simply switched to ngrok which gives you a valid wildcard SSL to test on and I was in business. Also, another gotcha is, if you are testing with Chrome DevTools open, make sure you turn off "Cache (While DevTools is Open)" setting. – Peter P. May 24 '20 at 21:40
  • Thanks! Drove me crazy too – RomanHotsiy Mar 22 '23 at 08:36
13

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
  • 8
    I had that box unchecked and it was still not caching correctly. That box states: "Disable cache (while DevTools is open)". – slm Oct 08 '14 at 17:31
2

This is addition to kievic answer

To force browser to NOT send Cache-Control header in request, open chrome console and type:

location = "https://your.page.com"

To force browser to add this header click "reload" button.

Kamil Kiełczewski
  • 85,173
  • 29
  • 368
  • 345
  • 1
    Much better than keep opening a new tab and the developer tool every time. And `location.href=''` should be enough. – Dinh Tran Dec 21 '22 at 07:18
0

Quite an old question, but I noticed just recently (2020), that Chrome sometimes ignores the Cache-Control headers for my image resources when browsing using an Incognito window.

"Sometimes" because in my case the Cache-Control directive was honored for small images (~60-200KB), but not for larger ones (10MB).

Not using Incognito window resulted in Chrome using the disk cached version even for the large images.

mediafreakch
  • 1,336
  • 1
  • 12
  • 19
-2

Another tip:

Do not forget to verify "Date" header - if server has incorrect date/time (or is located in another time zone) - Chrome will keep requesting resource again and again.

kolobok
  • 3,835
  • 3
  • 38
  • 54
  • That makes no sense. When a person from the USA goes on a website with a different time zone, caching still works. – Sainan Nov 06 '16 at 10:39
  • 1
    It makes a lot of sense to check for server clock skew. But yes first verify that all times are UTC. Timezone should not be an issue. – moodboom Mar 31 '17 at 18:29