Why is Chrome still caching this request? - google-chrome

I have a page with all the cache control goodies set, and yet, Google Chrome keeps pulling it from the cache. We emptied all navigation history but after one reload, Chrome caches it again :
Request URL:http://stuf.com/path/to/foo
Request Method:GET
Status Code:200 OK (from cache)
Response Headers
Accept-Ranges:bytes
Age:0
Cache-Control:no-cache, no-store, max-age=0, must-revalidate
Content-Encoding:gzip
Content-Language:fr
Content-Length:7289
Content-Type:text/html; charset=utf-8
Date:Fri, 17 Jul 2015 23:19:54 GMT
Expires:Fri, 01 Jan 2010 00:00:00 GMT
Server:nginx
Vary:Accept-Language, Cookie, Accept-Encoding
Via:1.1 varnish
X-Varnish:1867509088
X-Varnish-Cache:MISS
Request Headers
Provisional headers are shown
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.134 Safari/537.36
We do have varnish setup, but as you can see from X-Varnish-Cache, it's a miss. Plus, the status code section does state that Chrome is using the cache.

In your response header, Chrome states that the age is 0, i.e. the response has been cached for a second or less.
It should probably work if you wait for more than a second or include a cache validator: an ETag or a Last-Modified header which allows the browser to trigger a revalidation (conditional request) instead of a normal GET request.
The problem is likely the must-revalidate (which you do not need with max-age=0):
When the must-revalidate directive is present in a response received by a cache, that cache MUST NOT use the entry after it becomes stale to respond to a subsequent request without first revalidating it with the origin server
Without and ETag or Last-Modified header a revalidation is not possible.
Also, you can skip the Expires header:
If a response includes both an Expires header and a max-age directive, the max-age directive overrides the Expires header, even if the Expires header is more restrictive. This rule allows an origin server to provide, for a given response, a longer expiration time to an HTTP/1.1 (or later) cache than to an HTTP/1.0 cache.
from the RFC.

Related

Why does chrome not request more recent version of cached file?

I have a caching issue. Chrome does not always load newer versions of site assets, most often Javascript files loaded by Require.js. Right now I've been having this problem for over 24 hours with a particular file.
If I load the page with devtools (network tab) open, the offending files typically show a HTTP 200 response, but in the "Size" column it shows "(from cache)". In the Headers details it shows "Provisional headers are shown". Wireshark shows that the file is indeed not requested from the server.
Chrome shows the Last-Modified date of the file as Sat, 06 Dec 2014 01:27:55 GMT, but my below raw request to the server clearly indicates the file has changed much more recently.
If I do a raw request myself I don't see anything in the headers returned by the server that should cause this problem:
GET /js/path/to/file.js HTTP/1.1
Host: static.mydomain.com
User-Agent: Matt
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Vary: Accept-Encoding
Content-Type: application/javascript
Accept-Ranges: bytes
ETag: "4203477418"
Last-Modified: Fri, 16 Jan 2015 18:28:30 GMT
Content-Length: 5704
Date: Fri, 16 Jan 2015 21:05:06 GMT
Server: lighttpd/1.4.33
.... data here ...
The issue has been reported by chrome users on multiple OSes with different versions of chrome, but I do not typically receive reports of caching issues on other browsers. (Right now I'm on "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.71 Safari/537.36")
Edit:
The problem seems to be most offensive with files loaded by Require.js, though I have encountered it with javascript directly referenced in the page as well.
What am I missing here? Why won't chrome check for a new version of the file?
As it turns out, browsers have poorly documented behavior regarding caching when the Cache-Control header is not specified in the server response (well, at least when no caching behavior is specified). In general, it seems that in this case a browser determines how long to cache the item for based on the file's last modified date (if declared in the response), the current date, and ????
See: https://webmasters.stackexchange.com/questions/53942/why-is-this-response-being-cached
Sadly, Google's official page on HTTP caching does not mention what happens if the header is not set: https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching
Edit:
I ran across some more specific information about the heuristics used, here: What heuristics do browsers use to cache resources not explicitly set to be cachable?

Chrome over-caching .json files served from nginx

I'm using nginx and Dojo to build an embedded UI driven by a set of JSON files. Our primary target browser is Chrome, but it should work with all modern browsers.
Changing the JSON files can change the UI drastically, and I use this to give different presentations to different users. See my previous question for the details (Configure nginx to return different files to different authenticated users with the same URI), but basically my nginx configuration is such that the same URI with different users can yield different content.
This all works very well, except when someone switches to a different user. Some browsers will grab those JSON files from their own internal cache without even checking with the server, which leaves the UI display the previous user's presentation. Reloading the page fixes it, but boy! would I rather the right thing happened automatically.
The obvious solution is to use the various cache headers, but they don't appear to help. I'm using the following nginx directives:
expires epoch;
etag off;
if_modified_since off;
add_header Last-Modified "";
... which yields the following response headers:
HTTP/1.1 200 OK
Server: nginx/1.4.1
Date: Wed, 24 Sep 2014 16:58:32 GMT
Content-Type: application/octet-stream
Content-Length: 1116
Connection: keep-alive
Expires: Thu, 01 Jan 1970 00:00:01 GMT
Cache-Control: no-cache
Accept-Ranges: bytes
This looks pretty conclusive to me, but the problem still occurs with Chrome 36 for OS X and Opera 24 for OS X (although Firefox 29 and 32 do the right thing). Chrome is content to grab files from its cache without even referring to the server.
Here's a detailed example, with headers pulled from Chrome's Network debug panel. The first time Chrome fetches /app/resources/states.json, Chrome reports
Remote Address:75.144.159.89:8765
Request URL:http://XXXXXXXXXXXXXXX/app/resources/screens.json
Request Method:GET
Status Code:200 OK
with request headers:
Accept:*/*
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en-US,en;q=0.8
Authorization:Basic dm9sdGFpcndlYjp2b2x0YWly
Cache-Control:max-age=0
Connection:keep-alive
Content-Type:application/x-www-form-urlencoded
DNT:1
Host:suitable.dyndns.org:8765
Referer:http://XXXXXXXXXXXXXXXXXXXXXX/
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.125 Safari/537.36
X-Requested-With:XMLHttpRequest
and response headers:
Accept-Ranges:bytes
Cache-Control:no-cache
Connection:keep-alive
Content-Length:2369
Content-Type:application/octet-stream
Date:Wed, 24 Sep 2014 17:19:46 GMT
Expires:Thu, 01 Jan 1970 00:00:01 GMT
Server:nginx/1.4.1
Again, all fine and good. But, when I change the user (by restarting Chrome and then reloading the parent page), I get the following Chrome report:
Remote Address:75.144.159.89:8765
Request URL:http://suitable.dyndns.org:8765/app/resources/states.json
Request Method:GET
Status Code:200 OK (from cache)
with no apparent contact to the server.
This doesn't seem to happen with all files. A few .js files are cached, most are not; none of the .css files seem to be cached; all the .html files are cached, and all of the .json files are cached.
How can I tell the browser (I'm looking at you, Chrome!) that these files are good at the moment it requests them, but will never again be good? Is this a Chrome bug? (If so, it's strange that Opera also shows the problem.)
I believe I've found the problem. Apparently "Cache-Control: no-cache" is insufficient to tell the browser to, um, not cache the data. I added "no-store":
Cache-Control:no-store, no-cache
and that did the trick. No more caching by Chrome or Opera.
I had the same problem, with json being cached...
If you control the client application-code, a possible workaround is to just add a random-value query-parameter at the end of the URL.
So instead of calling:
http://XXXXXXXXXXXXXXX/app/resources/screens.json
you call, for example:
http://XXXXXXXXXXXXXXX/app/resources/screens.json?rand=rrrrrrrrrr
where rrrrrrrrrr is some random-value that is different in each call.
Then, the browser will not be able to reuse any cached values.

Why does Browser still sends request for cache-control public with max-age?

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.
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.
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.
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.
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.
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.

Chrome not updating CSS file for offline-enabled HTML5 website

I have an offline-enabled website that uses a cache manifest. I'm finding with Chrome that it is serving an older version of my stylesheet, even if I do a "Empty Cache and Hard Reload"
If I append ?foo=bar to the URL of the page or the CSS, the new version of the CSS is delivered.
My manifest is dynamically generated at /Manifest/Index (e.g. )
If I open the page in Chrome and check out Fiddler, I see a single request is made to the web server, as expected:
# Result Protocol Host URL Body Caching Content-Type Process Comments Custom
6 200 HTTP 10.6.4.67 /Manifest/Index 2,476 no-cache Expires: -1 text/cache-manifest; charset=utf-8 chrome:5484
Here is the header detail for /Manifest/Index
GET /Manifest/Index HTTP/1.1
Host: 10.6.4.67
Connection: keep-alive
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.11 (KHTML, like Gecko)
Chrome/23.0.1271.97 Safari/537.11
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3
HTTP/1.1 200 OK
Date: Thu, 10 Jan 2013 17:59:42 GMT
Server: Microsoft-IIS/6.0
X-Powered-By: ASP.NET
X-AspNet-Version: 4.0.30319
X-AspNetMvc-Version: 4.0
Cache-Control: no-cache
Pragma: no-cache
Expires: -1
Content-Type: text/cache-manifest; charset=utf-8
Content-Length: 2476
Can anyone tell me why on earth a CSS file reference in this cache-manifest isn't updating unless I append a cache-busting querystring variable to the CSS? Especially even if I empty Chrome's cache??!
More info:
If I update the cache-manifest, I can open up Chrome's console and see the App Cache events fire:
Document was loaded from Application Cache with manifest /Manifest/Index
Application Cache Checking event
Application Cache Downloading event
Application Cache Progress event (0 of 61) http://x.x.x.x/Content/themes/base/jquery.ui.progressbar.css
Application Cache Progress event (1 of 61) http://x.x.x.x/Content/themes/base/jquery.ui.accordion.css
Snip
Application Cache Progress event (54 of 61) http://x.x.x.x/Content/Site.css
I do notice that some of the items in this list, like Site.css, are underlined. Why is that?
Thanks,
Chris
Clear your appcache in Chrome using: chrome://appcache-internals/ and remove it there.
Also you need to rebuild your manifest file each time you change the files contained in it for the new copied to be downloaded.
This is accomplished by using a random number in your manifest and generating it when files are edited.
For example in node.js
function generateCacheManifest(...) {
manifest = 'CACHE MANIFEST';
manifest += '#version ' + Math.random();
...
}
Yes the random number can be in a comment. The point is that Chrome will check the cache manifest and when it sees that nothing has changed it will not fetch the updated files.
Change a file, change your manifest, it's that simple.

Chrome loads a text/html file but shows status "failed" and does not render on screen

Still facing a weird issue with Google Chrome. I have a text/html page generated from a php source code. This page loads well and is well displayed on any popular browsers but Chrome. When the source code has just been saved, Chrome loads and render the file the right way. Even if I simply added or removed a space character. Next, if I try to refresh the page, Chrome displays a blank page and shows an error in the Developper Tools panel (see screenshot) indicating a "failed" status. But if I check the HTTP response headers, everything seems to be fine, including the HTTP status: 200 OK.
HTTP/1.1 200 OK
Date: Mon, 17 Sep 2012 08:37:03 GMT
Server: Apache/2.2.3 (CentOS)
X-Powered-By: PHP/5.3.14
Expires: Mon, 17 Sep 2012 08:52:03 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Connection: close
Transfer-Encoding: chunked
Content-Type: text/html; charset=UTF-8
Bellow is the HTTP response headers just after saving the source and getting a correct rendering. No change (except time related information)
HTTP/1.1 200 OK
Date: Mon, 17 Sep 2012 08:56:06 GMT
Server: Apache/2.2.3 (CentOS)
X-Powered-By: PHP/5.3.14
Expires: Mon, 17 Sep 2012 09:11:07 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Connection: close
Transfer-Encoding: chunked
Content-Type: text/html; charset=UTF-8
I also checked the HTTP request headers, they are the same in both cases:
Working case:
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Charset:ISO-8859-1,utf-8;q=0.7,*;q=0.3
Accept-Encoding:gzip,deflate,sdch
Accept-Language:fr-FR,fr;q=0.8,en-US;q=0.6,en;q=0.4
Cache-Control:max-age=0
Connection:keep-alive
Cookie:PHPSESSID=qn01olb0lkgh3qh7tpmjbdbct1
Host:(hidden here, but correct, looks like subsubdomain.subdomain.domain.tld)
User-Agent:Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1180.89 Safari/537.1
Failing case:
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Charset:ISO-8859-1,utf-8;q=0.7,*;q=0.3
Accept-Encoding:gzip,deflate,sdch
Accept-Language:fr-FR,fr;q=0.8,en-US;q=0.6,en;q=0.4
Cache-Control:max-age=0
Connection:keep-alive
Cookie:PHPSESSID=qn01olb0lkgh3qh7tpmjbdbct1
Host:(also hidden)
User-Agent:Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1180.89 Safari/537.1
I noticed that even if the page failed, some other resources (javascript, style sheets) are successfully loaded or retrieved from the local cache. I can also access the HTML source code successfully every time, could the page be rendered or not (the HTML code is what it's expected to contain).
I also ran Wireshark in order to see if there would be something wrong while transferring data or something, but everything seems to be OK on this side too.
I read something on Google about content-length that would make Chrome fail if the information provided in the HTTP headers differs from the effective size of the delivered file. It does not seem to me it would be the case here as content-length is not provided.
Any help would be welcome! Thanks!
To those who are still encountering the issue:
add
setEnv downgrade-1.0
to your .htaccess, for me it works as temporary fix. It disables chunked transfers.
Another solution is to set user agent to IE, apparently it does the same...
Actual issue is somehow related to server configuration, I am also seeing segmentation fault errors.
Site I am encountering this behaviour runs on PHP 5.3.27 over HTTPS.
edit: It doesn't matter if site is accessed over HTTPS or HTTP.
edit2: The cause for this error was one extremely long line, splitting it into multiple lines solved the problem.