Reputation: 8297
IE (7 -10) doesn't seem to respect expires. I opened fiddler and was checking. if the response had a etag then it does a 304 otherwise it does a 200 for the resource which had an expiry in 1 year future. I tried setting last modified as well. it doesn't seem to work. In chrome when there is an expires tag..it doesn't even go out to the server(for a 304) it has it cached. Here is some of the Fiddler headers
Req Headers
GET /geoip/city?country=US&state=ID HTTP/1.1
X-Requested-With: XMLHttpRequest
Accept: */*
Referer: http://localhost/register/BG/57ac5960-f0d5-11e3-90d1-af2b2634c624
Accept-Language: en-US
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko
Connection: Keep-Alive
Host: localhost
Cookie: connect.sid=s%3AntN3Tq9zXgrnlo5YOR1bsSa0lHE987Nv.aBbljhmG5tpfYcIXMgonxnhhWaWwd%2BTQ4jIKLnqL4us
Response Headers
HTTP/1.1 200 OK
X-Powered-By: Express
Vary: X-HTTP-Method-Override, Accept-Encoding
expires: Sun Jul 05 2015 23:15:21 GMT-0400 (Eastern Daylight Time)
Content-Type: application/json; charset=utf-8
Content-Encoding: gzip
Date: Mon, 07 Jul 2014 03:15:21 GMT
Connection: keep-alive
Transfer-Encoding: chunked
and with E-tag
req Headers
GET /geoip/city?country=US&state=ID HTTP/1.1
X-Requested-With: XMLHttpRequest
Accept: */*
Referer: http://localhost/register/BG/57ac5960-f0d5-11e3-90d1-af2b2634c624
Accept-Language: en-US
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko
Host: localhost
If-None-Match: W/"101c-2996882950"
Connection: Keep-Alive
Cookie: connect.sid=s%3AntN3Tq9zXgrnlo5YOR1bsSa0lHE987Nv.aBbljhmG5tpfYcIXMgonxnhhWaWwd%2BTQ4jIKLnqL4us
Response header
HTTP/1.1 304 Not Modified
X-Powered-By: Express
Vary: X-HTTP-Method-Override
expires: Sun Jul 05 2015 23:18:47 GMT-0400 (Eastern Daylight Time)
ETag: W/"101c-2996882950"
Date: Mon, 07 Jul 2014 03:18:48 GMT
Connection: keep-alive
As per suggestion from Ruud..Here is the req/response
GET /geoip/city?country=US&state=MO HTTP/1.1
Cache-Control: public, max-age=31536000
Accept: */*
X-Requested-With: XMLHttpRequest
Referer: http://localhost/register/BG/57ac5960-f0d5-11e3-90d1-af2b2634c624
Accept-Language: en-US
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko
Connection: Keep-Alive
If-None-Match: W/"3bf9-3115988671"
Host: localhost
Cookie: connect.sid=s%3AZvwd9g7PAbQl7QHVx0ucpBMNnELll1R_.6KIvAtRWv9FK3zxxXVZfJBCpSv962zxLeTkvGd7mQq8
HTTP/1.1 304 Not Modified
X-Powered-By: Express
Vary: X-HTTP-Method-Override
expires: Mon Jul 06 2015 08:37:49 GMT-0400 (Eastern Daylight Time)
Cache-Control: public, max-age=31536000
last-modified: Sat Jul 07 2012 08:37:49 GMT-0400 (Eastern Daylight Time)
ETag: W/"3bf9-3115988671"
Date: Mon, 07 Jul 2014 12:37:49 GMT
Connection: keep-alive
Upvotes: 0
Views: 3104
Reputation: 11028
One possible explanation is the fact that:
Expires: Sun Jul 05 2015 23:15:21 GMT-0400 (Eastern Daylight Time)
is not a valid RFC 1123 date. Try changing the response-header field to:
Expires: Sun, 05 Jul 2015 23:15:21 GMT
RFC 2616 states:
HTTP/1.1 clients and caches MUST treat other invalid date formats, especially including the value "0", as in the past (i.e., "already expired").
From there, the web browser's behavior depends on whether or not there is a Last-Modified
and/or ETag
response-header field.
Last-Modified
/ ETag
: since Expires
has an invalid date, and there is no Cache-Control
to fall back on (you did test Cache-Control
, but with Last-Modified
/ ETag
, not without), caching may well be disabled; the client will send a request, the server will respond with a 200.Last-Modified
/ ETag
: caching may be enabled, but Expires
has an invalid date, so the client is forced to send a request to verify the cache is not stale. The server responds with a 304 to confirm the cache is OK.From your story I gather this is precisely what IE 7-10 does.
On the other hand, RFC 2616 makes the note:
Recipients of date values are encouraged to be robust in accepting date values that may have been sent by non-HTTP applications, as is sometimes the case when retrieving or posting messages via proxies/gateways to SMTP or NNTP.
So some browsers may be more liberal than others, and do their utmost best to parse your date (Chromium issue 153759 seems to suggest just that). This might explain why Chrome hits the cache when IE does not.
Note: you may consider adding Cache-Control: public, max-age=31536000
to the response header, in addition to (or as a replacement of) Expires
. See also:
EDIT: I did a very simple test with IE9. On a Linux machine, I repeatedly ran the following command (making it act as a single-shot web server):
cat h1.txt b1.txt | sudo nc -l 91
This is my h1.txt
; since I created it on a Linux machine I had to use unix2dos
to ensure each line was terminated with \r\n
. Relevant response-header fields are Expires
and Last-Modified
.
HTTP/1.1 200 OK
Content-Type: text/html;charset=utf-8
Date: Sat, 12 Jul 2014 20:07:43 GMT
Expires: Sun, 05 Jul 2015 23:15:21 GMT
Last-Modified: Sat, 12 Jul 2013 20:07:43 GMT
Server: WEBrick/1.3.1 (Ruby/1.9.2/2014-01-23)
Content-Length: 252
Connection: keep-alive
b1.txt
is an HTML page with a piece of JavaScript calling XMLHttpRequest
, sending an HTTP request to the same page (because I was too lazy to set up another page).
<html>
<head>
<title>Test</title>
</head>
<body>
<button onclick="SendReq()">Send request</button>
<script>
function SendReq() {
var rq = new XMLHttpRequest();
rq.open('GET', 'http://192.168.1.103:91/', true);
rq.send();
}
</script>
</body>
</html>
I didn't have Fiddler installed; I used Wireshark instead (filtering on tcp.port == 91
) to monitor the traffic. And indeed, I can click the button on my web page as often as I want, there is no traffic, until I clear IE9's cache.
This means IE9's cache works alright; the problem must be on the web server; more specific, in the response header. Any small mistake could disrupt caching. Your original Expires header field (with the non-GMT date) was an excellent example of that.
And as pointed out by Pierre, do put Last-Modified
and/or ETag
in the response header, otherwise IE is likely to make the roundtrip to the web server even when the page is present in the cache. But I suspect that is the case for every web browser, not just legacy IE.
Upvotes: 0
Reputation: 430
I think you don't understant what the Expires is intended for. It's just something to tell to the browser: "keep it in cache until..." But it doesn't tell: "and don't check if it's not modified"! So use "Expires", and use "Last-modified" too, with both correct (valid RFC 1123) date value: "Sun, 05 Jul 2015 23:15:21 GMT". It should work.
Upvotes: 0
Reputation: 11028
Your HTTP request does not contain an If-Modified-Since
header. This typically means the page has not been cached. This is probably due to the absence of a Cache-Control
header. Without that header, a web browser will probably apply its own default caching behavior. In the case of IE7/8/9/10, that may well be something like: "Your URL has a query string, let's not cache it."
Please try adding this header to the HTTP request:
Cache-Control: public, max-age=31536000
Your HTTP request contains X-Requested-With: XMLHttpRequest
, so I assume you are using XMLHttpRequest to send HTTP requests to the web server. You can probably add the header like this:
req.setRequestHeader("Cache-Control", "public, max-age=31536000");
In addition to the above, you may need to have a Last-Modified
header in the HTTP response; the client may need this date/time to put in the If-Modified-Since
header upon the next HTTP request.
Use Fiddler to verify that:
Cache-Control
Last-Modified
Cache-Control
and If-Modified-Since
When all else fails, you might even consider pushing your own If-Modified-Since
header into the HTTP request.
Documentation of aforementioned headers can be found in sections 14.9, 14.25 and 14.29 of http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
Upvotes: 1