views:

511

answers:

2

I have a page that loads a lot of images, css and javascript. I've added a far future Expires header and set Cache-Control to public on these external dependencies so they should be cached. But every time I do a Post/Redirect/Get chrome tries to load these again. This behavior is very similar to reloading the page. I've added ETags and handle the If-None-Match header which helps a bit, but it still generates too many useless requests.

How do I tell chrome and safari to get the files from cache?

chrome   NOK
safari   NOK
firefox  OK
ie       OK

Also see Full page reload on Post/Redirect/Get ignoring cache control on the google support forum.

Clarification:

I don't want the browser to request image1.png twice. It should be cached.

200 GET  page1.html
200 GET  image1.png (Cache-Control: public, Expires and ETag)
302 POST action.asp (form submitted from page1.html, redirects)
200 GET  page2.html
304 GET  image1.png (If-None-Match)

Example:

I've created a simple example to illustrate the problem.

http://crydust.be/lab/prg/

Headers:

The headers I send with the image are:

HTTP/1.1 200 OK
Date: Fri, 18 Jun 2010 11:30:22 GMT
Server: Apache
Cache-Control: public, max-age=86400
Expires: Sat, 19 Jun 2010 11:30:24 GMT
Etag: "123"
Content-Length: 866
Content-Type: image/png

Which should make it cached for 24 hours. There is no Vary: * or anything like that.

Update: This behavior is now also present in Safari Mobile on iOS 4. A horible regression in page-load speed.

Update: There is a bugreport about this issue in the webkit bugzilla. Bug 38690 - Submitting a POST that leads to a server redirect causes all cached items to redownload

Update: The problem persists on iOS 4.0.1

Update: The problem persists on iOS 4.1

A: 

When you F5/refresh in Chrome, Safari or IE8 all the GET resources are requested again, even if they've been cached.

If you watch the request/response with the dev tools or Fiddler you'll see that the server responds with an HTTP 304 status and no content. This tells the browser that they don't need to download it again and that they can continue to use the cache.

In Chrome's dev tools' Resource tab files refreshed like that will have a latency time, but a download time of 0ms.

If you reload the page by leaving and returning you'll find that these cached files are not retrieved again and the server is not checked.

This behaviour of F5/refresh for GET static resource is correct - it's FX and IE6 that are doing it wrong. It also helps with the confusing CTRL+F5 command that most users don't know about.

You can't cache POST or pages that return a temporary HTTP redirect:

POST changes data and should always prompt before being sent again, and its results are never cached.

Redirects are handled at a low level in the HTTP stuff - below caching. Really it tells the browser to get the resource from somewhere else and while it can cache that it hasn't cached the redirect and needs to check again.

You should be able to cache a 301 permanent redirect, but a 302 or 303 temporary redirects shouldn't be cached according to the HTTP spec.

Keith
The user didn't press F5. The browser behaves as if F5 was pressed after a post/redirect/get. I don't want to cache the redirect, just the static images.
Kristof Neirynck
@Kristof Neirynck - Ahh, so the post returns a redirect and the page pings all the static content with 304s, but if you link straight to it you get the static content locally cached? That does seem like a bug. Check the response headers on the static content - some of them (such as Vary: *) cause issues with client caching in some browsers. You might find a workaround there.
Keith
A: 

F5 reloads all the page's resources in some browsers, so they ignore the cache headers and ask for every resource again.

If you want to "cache" POST pages you have to convert those pages in static resources, i.e. generating a .html file from the .php for example and then serve the .html as a static resource.

This is valid ONLY if the content of the page doesn't change

RDAM
I'm not pushing F5. I'm doing a post redirect get.
Kristof Neirynck