Forum Moderators: phranque

Message Too Old, No Replies

Cache-Control: max-age=0 interfering with images and css

         

JS_Harris

10:32 pm on Mar 8, 2016 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



I'm having some difficulty removing Cache-Control: max-age=0 from the header response of images as follows

http://www.example.com/image.jpg
GET /image.jpg HTTP/1.1
Host: www.example.com
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.5
Accept: image/png,image/*;q=0.8,*/*;q=0.5
User-Agent: some user agent(whatever)
Referer: http://www.example.com/some-page
Connection: keep-alive
Cache-Control: max-age=0 <------ Where is this coming from ?

HTTP/1.1 200 OK
Date: Tue, 08 Mar 2016 23:02:36 GMT
Server: Apache
Accept-Ranges: bytes
Content-Length: 32176
Cache-Control: max-age=31530000 <---- CORRECT (1 yr)
Vary: Accept-Encoding
Keep-Alive: timeout=5, max=98
Connection: Keep-Alive
Content-Type: image/jpeg

It doesn't matter which browser or online service I use the Cache-Control: max-age=0 is being set which is causing the correct max-age response to be ignored. When I run the site through pagespeed, for example, it tells me to add cache to images. This isn't happening to any php or html page but is happening to all images, css files, js files etc.

The only image file specific code in my htaccess file is this and it seems to be working, but being overridden.
<FilesMatch "\.(jpg|jpeg|png|gif|ico|css)$">
Header set Cache-Control "max-age=31530000"
</FilesMatch>


Nowhere within my htaccess file do I set a Cache-Control: maxe-age=0 response, nowhere! No etag or pragma either. How can I make the server stop adding max-age=0?

whitespace

11:14 pm on Mar 8, 2016 (gmt 0)

10+ Year Member Top Contributors Of The Month





Cache-Control: max-age=0 <------ Where is this coming from ?



The header you've quoted here is part of the request headers as sent from the browser?

Where are you getting the "correct" response headers that you quote below that? Are those not the actual response headers from your site?

lucy24

11:58 pm on Mar 8, 2016 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



Where is this coming from?

Do you mean that this request header is present all the time, not just in things like search-engine requests where it's a standard feature?

JS_Harris

1:02 am on Mar 9, 2016 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



It's there in the request ALL the time. Yes, the correct response below is what is returned by my browser. I see the max-age=0 in the request regardless of browser on several computers. Several online services that monitor page speed all offer adding cache to images as a suggestion, they see it too. Fetching as Google confirms it.

The response headers are fine, the request headers include max-age= 0 when my pages are the referer, which is essentially every page load.

The site is static html, no wordpress or other CMS is involved. I didn't know max-age=0 could be appended to the request all the time but, well, there it is.

The only documentation I could find on it was from 2008 here - [bugzilla.mozilla.org...]

Only seems to affect .jpg, .css, .js etc but not .php or .html pages.

lucy24

3:19 am on Mar 9, 2016 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



That linked article is specifically about Refreshing, isn't it? Seems like the browser should then be sending an If-Modified-Since header, not a "send me a brand-new copy of everything, even if it hasn't changed since 2013 and my cached copy is from last week". But we digress.

:: detour to check something ::

OK, it's not an intrinsic feature of an ordinary image request. (I don't log non-page headers, so the only records I've got are from blocked or not-found image requests, which almost by definition means images that don't have one of my pages as referer.) The Cache-Control header is, for example, absent from GoogleImageProxy requests.

:: wandering off in horror at sheer number of blocked image requests that I never paid any attention to ::

JS_Harris

3:37 am on Mar 9, 2016 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



That was a firefox article, they noticed the problem but didn't resolve it. Here is someone experiencing it with chrome in 2012 - [superuser.com...]

The problem I'm having is that It's not just on refresh, it's on every page load, but only for images and css/js files.

lucy24

6:22 am on Mar 9, 2016 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



but only for images and css/js files

That part makes sense. There would be no reason to include the Cache-Control header on the initial page request, before they set foot on your site, because they have no reason to think they're supposed to include it. It's something about that page--that is, all your pages--that's making them add the caching business to requests for supporting files.

Come to think of it: If someone sticks around and goes from one page to another on your site, do those subsequent page requests also have an unwanted Cache-Control header?

Can we have a look at the response headers for a page request? Both entry and non-entry, if they're different. There's got to be something in there.

:: wait, stop, rewind ::

Connection: keep-alive
Do they all say this, or is it just the random two you quoted? Mine never-- I mean literally never, I checked-- say anything but "close". Making me wonder what's the point of even having the header, if even the crudest robot just says the same thing. What do the page request headers say?

whitespace

9:21 am on Mar 9, 2016 (gmt 0)

10+ Year Member Top Contributors Of The Month



Connection: keep-alive


Do they all say this, or is it just the random two you quoted? Mine never-- I mean literally never, I checked-- say anything but "close". Making me wonder what's the point of even having the header, if even the crudest robot just says the same thing. What do the page request headers say?


FWIW, I see "Connection: keep-alive" (lowercase) on all request headers (including Googlebot), however, my "live" server responds with a "Connection: close". My development server always responds "Connection: Keep-Alive" (CamelCase) - not sure why the difference, but they are different platforms, different versions.

I also see the "Cache-Control: max-age=0" request header sent from Chrome.

However, none of that seems to prevent the resource being cached in my case. I see the 304 Not Modified response reported by the browser.

If I specifically disable caching in the browser, then the Cach-Control request header changes to "Cache-Control: no-cache".

JS_Harris

9:54 am on Mar 9, 2016 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



*update*

- Static html pages, everything about them can be cached for a long time without problem
- Cache-Control: max-age=0 is returned in the request header for every file
- The proper max-age value is returned in the response header for every page and file(but ignored)
- Pages/files always return 200, not 304
- Header unset ETag is in htaccess file
- FileETag None is in htaccess file
- Expires is unset in the htaccess file
- Pragma is unset in the htaccess file
- Max-age + last modified worked well for caching on other sites I own, but not this one

*solution found*
The site was an addon domain and the primary domain unset the Expires response as well. Without Expires in the primary domain the Expires unset command in the addon domain wasn't properly being followed. The initial page request was handled properly in the addon domain but images and files on that page were failing to cache properly as a result. In the absence of a proper directive browsers add Cache-Control: max-age=0 to the request.

Ironically, after slightly modifying the primary domain htaccess rules as above, the max-age=0 is still being appended to all requests but it is now being ignored, all pages/images return a proper 304 not modified response.

I need a new host, this one is driving me insane. Every single page has max-age=0 in the request and max-age=proper length in the response. At least visitors now get a proper 304 response and can cache all pages and files even if the header request says don't do it.

whitespace

1:00 pm on Mar 9, 2016 (gmt 0)

10+ Year Member Top Contributors Of The Month



I need a new host, this one is driving me insane. Every single page has max-age=0 in the request ...


This doesn't really have anything to do with the host - if that is what you are implying? The "max-age=0" is sent from the client as part of the request headers (which would seem to be "normal" in the case of a browser refresh.).

Not sure why you would need to explicitly unset the Expires header; unless there is something explicitly setting it? However, all modern browsers should ignore it anyway if there is a "Cache-Control: max-age=NNN" header present. (It's generally easier to use mod_expires and ExpiresByType, which sets both the Cache-Control and Expires headers in one go.)

Just to add, I only see the "Cache-Control: max-age=0" request header (and the 304 response) if I explicitly do a browser refresh. If I simply navigate from page to page then the resource is pulled from the browser cache and I see a 200 OK status - an additional column (in Chrome's inspector) states "(from cache)". There is no 304 response, since there is no external request to the server (as expected).

...the max-age=0 is still being appended to all requests but it is now being ignored, all pages/images return a proper 304 not modified response.


It's not exactly being "ignored". The "max-age=0" in the request is simply a request for revalidation. And your server is then correctly validating the request to return a 304 response. However, what is perhaps missing from the request headers posted initially is an "If-Modified-Since" header (as lucy24 mentioned), perhaps because there is no "Last-Modified" header in the initial response(?) - without that I'm not sure how the server could successfully revalidate the request. (?)

So, I assume the response/request headers now look a bit different to what you posted initially?

JS_Harris

5:53 pm on Mar 9, 2016 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



Not sure why you would need to explicitly unset the Expires header
In the primary domain, if I set something via htaccess it is reiterated for all addon domains(completely different websites), that's not ideal. example: If I add a nosniff header on the primary domain and the addon domain it becomes nosniff,nosniff for the addon domain. If, god forbid I add a nosniff header entry on the primary domain and sniff entry on the addon domain(no reason to, just an example) it becomes 'nosniff,sniff' in the addon domain's results.

max-age=0, must revalidate, nocache, max-age=123456789 is not normal but the host insists on adding the primary domain htaccess rules to the headers of all addon domains. I AM suggesting that's not right. It probably leads to a lot of webmaster confusion too when their entries don't work as expected and they don't see anything wrong with their access file and don't have any reason to suspect the behavior.

So, I assume the response/request headers now look a bit different to what you posted initially?
Yes, the response/request headers now look a bit different to what I posted initially but only because they make no sense to the addon domain. When I realized that what the primary domain has in its htaccess file is more important than what is in the addon domain's htaccess file I worked it out. It's still wrong, and broken, but it works now.

example: I don't specify a max-age= time in the addon domain at all but all headers have one, it's in the htaccess file of the primary domain(different website completely). Very frustrating.

This has turned into more of a rant but consider it resolved. Nobody can really help when things in the htaccess file are ignored/duplicated/cascaded based on the contents of the htaccess file of an entirely different site.

edit: my options include getting a new hosting plan for each individual site or moving a real website out of the primary domain spot and replacing it with a placeholder domain that doesn't require an htaccess file at all. No rules = no conflicts. Thanks for trying to help.

lucy24

8:45 pm on Mar 9, 2016 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



In the primary domain, if I set something via htaccess it is reiterated for all addon domains(completely different websites), that's not ideal.

Yes, that's an inherent property of the primary/addon structure. The best remedy-- other than picking a host that uses the "userspace" structure* instead-- is not to use your "primary" domain for anything-- not even testing. Find some useless name and call it your primary; you can then treat your "primary" domain as a userspace, with no site-specific rules.

Unfortunately you can't change this after the fact, though I guess you could ask. ("I want to change my primary domain from example.com to example.org".) Even if you can do it without changing hosts, it will involve a bit of downtime.

Edit:
edit: my options include getting a new hosting plan for each individual site or moving a real website out of the primary domain spot and replacing it with a placeholder domain that doesn't require an htaccess file at all. No rules = no conflicts.
Took the words right out of my mouth. Well, almost. You can continue using the "primary" htaccess for things that are shared by all sites, such as general access control. Definitely don't use mod_rewrite in this location. But things like <Files> envelopes to grant universal access to every site's robots.txt could certainly stay here.


* When I first set up my hosting, I didn't know about these two different configurations. It was just blind luck that I landed on a "userspace" host.

whitespace

9:08 pm on Mar 9, 2016 (gmt 0)

10+ Year Member Top Contributors Of The Month



@lucy24: What structure does the "userspace" structure take?

lucy24

9:22 pm on Mar 9, 2016 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



What structure does the "userspace" structure take?

Physically it's just like a "primary" except that, well, there is no primary.

/filepath/users/your-name/
and then
/filepath/users/your-name/example.com/
/filepath/users/your-name/example.org/
/filepath/users/your-name/example.net/
and so on.

Then, in addition to the /example.tld/ htaccess files, you can also put one at the next higher level-- what you think of as the "primary". Not all directives work here; for example "Options" (as in, -Indexes or +Includes) has to be site-specific. But I can use <Files> envelopes, and most importantly, all access controls can be done once and for all.

JS_Harris

10:01 pm on Mar 9, 2016 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



I think I'll treat the primary domain as a CDN moving forward, it's not much use to me as an actual site right now.