22

I have a situation where my (embedded) web server is sending Expires header, but the browser does not seem to respect the header setting, i.e., if I refresh the page, the browser requests the resources that are supposed to be cached. Following are the headers that are getting exchanged:

https://192.168.1.180/scgi-bin/ajax/ajax.cgi

GET /scgi-bin/ajax/ajax.cgi HTTP/1.1
Host: 192.168.1.180
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.0.11) Gecko/2009060215 Firefox/3.0.11 (.NET CLR 3.5.30729)
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
Cache-Control: max-age=0

HTTP/1.x 200 OK
Date: Wed, 24 Jun 2009 20:26:47 GMT
Server: Embedded HTTP Server.
Connection: close
Content-Type: text/html
----------------------------------------------------------
https://192.168.1.180/scgi-bin/ajax/static.cgi?fn=images/logo.jpg&ts=20090624201057

GET /scgi-bin/ajax/static.cgi?fn=images/logo.jpg&ts=20090624201057 HTTP/1.1
Host: 192.168.1.180
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.0.11) Gecko/2009060215 Firefox/3.0.11 (.NET CLR 3.5.30729)
Accept: image/png,image/*;q=0.8,*/*;q=0.5
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
Referer: https://192.168.1.180/scgi-bin/ajax/ajax.cgi
Cache-Control: max-age=0

HTTP/1.x 200 OK
Date: Wed, 24 Jun 2009 20:26:47 GMT
Server: Embedded HTTP Server.
Connection: close
Expires: Wed, 1 Jun 2011 20:00:00 GMT
Content-Type: image/jpg
----------------------------------------------------------

The ajax.cgi returns an html page with a logo graphic (via the static.cgi script), which I'd like cached, but the browser is asking for the logo on every refresh.

BartoszKP
  • 34,786
  • 15
  • 102
  • 130
user128602
  • 253
  • 1
  • 3
  • 6
  • I see you're working over HTTPS. Could that be the reason no caching is done as you expect it? Can you try a HTTP only version? – mark Jul 07 '09 at 06:56

4 Answers4

18

The browser ignores the Expires header if you refresh the page. It always checks whether the cache entry is still valid by contacting the web server. Ideally, it will use the If-Modified-Since request header so that the server can return '304 Not modified' if the cache entry is still valid.

You're not setting the Last-Modified header, so the browser has to perform an unconditional GET of the content to ensure that it is up to date.

Some rules of thumb for setting Expires and Last-Modified are described in this blog post:

http://blog.httpwatch.com/2007/12/10/two-simple-rules-for-http-caching/

HttpWatchSupport
  • 2,804
  • 1
  • 17
  • 16
14

What are you doing in your browser? I looks like you click the reload button or even something like shift+Reload. Normally, the browser wouldn't send a Cache-Control: max-age=0 header. That means the browser has thrown away the cached image and wants to get it again.

If you just navigate to another page and then back again, the browser should respect your Expires header.

Additionally, you could add a Cache-control: public header to your response. That allows proxies and the browser explicitly to cache the image.

chris166
  • 4,769
  • 4
  • 24
  • 25
  • 1
    This sure seems right. The browser (Firefox?) is sending max-age=0, which means it doesn't want any response older than 0s, ie, it wants to hit the origin web server. This is the definition of "refresh". Navigate away from your page, then paste in the URL again and see what happens. – Jim Ferrans Jun 25 '09 at 06:47
  • Indeed, I was doing a page reload, and I was expecting the browser to reload the html but not all the cached resources as well. I thought you had to do shift-click (or control-click? can't remember) to force the browser to invalidate cache on all the resources. I guess my understanding is incorrect? – user128602 Jun 25 '09 at 07:26
  • I'm not sure about this either. I think browsers behave differently on F5/Reload button with/without Shift. – chris166 Jun 25 '09 at 10:24
  • 1
    @user128602 a refresh ignores any Expire received, but there's still a chance to make use of browser caching capabilities on refresh, which is to ensure your server sends the modification time of files. Normally it does unless you're generating contents (like images) from a script rather than direct browser-server download. If server sends modification time, the next request a brower makes (including reload) will send "if-modified" to the server. If the server responds with "not-modified" then no download is performed. A CTRL+Refresh means to omit "if-modified" checks beside ditching cache. – doc_id Sep 19 '12 at 14:25
1

Any errors in your https certificate will cause the browser to not respect your headers.

Try it without https and see if it works over plain http.

See this answer https://stackoverflow.com/a/17716911

Community
  • 1
  • 1
10us
  • 1,622
  • 18
  • 13
0

The CGI script looks like it has a timestamp parameter...this isn't changing, is it? The browser should be treating each unique URL as a different object in the cache, so if that is updating with every request, it won't match with the cached image.

Additionally, the Expires field is not exactly in RFC 1123 format, because you need two digits for the date. This may or may not be an issue, but it's something to check. The browser is including Cache-Control: max-age=0, which indicates that it believes its cache to be potentially out of date.

Once the server gets this validation request, it can return 304 (Not Modified), or 200 (OK), as it is doing currently.

Dave Bauman
  • 9,252
  • 1
  • 19
  • 19