views:

362

answers:

3

In our project, we have a whole bunch of small css/js files, so when we build views we find ourselves writing many <link> or <script> tags, forcing the browser to make many requests for our css/js content. To remedy this, we started looking for a way for server to shore that all up into one request that dumps every css file or every js file associated with the action into the response.

Without going into too much detail, we created a Helper class that accepts the files, concatenates them, and renders a tag like so:

<script type="text/javascript" src="/content/js15628453.rails"></script>

The ContentController then has a default action which uses 'js15628453' to find where the Helper stored the concatenated file and streams it out. This works really well.

However, as Firebug reports it, the browser always sends a request to "/content/js15628453.rails" to get the concatenated file, despite the fact that the URL is always the same and the response is always the same. I've tried all types of combinations of the HTTP Cache-Control, Expires, Last-Modified, etc headers, but have yet to get something that Firebug reports as loaded from the cache.

Why might the browser be ignoring those headers? Are there any other options I can try to force it to be cached?

+2  A: 

Well, I figured this out so for the benefit of those who may find this in a search engine I'll go ahead and give an answer to my own question.

Basically, I had to write the logic to set a 304 status myself:

DateTime lastModified = // some date
string ifModifiedSince = Request.Headers["If-Modified-Since"];
if ( ifModifiedSince != null )
{
 var requestDate = DateTime.Parse( ifModifiedSince );
 if ( requestDate <= lastModified )
 {
  CancelView();
  Response.StatusCode = 304;
  return;
 }
}

Response.CachePolicy.SetLastModified( lastModified );

// Logic to write the file to the OutputStream

I had incorrectly assumed the browser would just use its cached copy if it existed and hadn't expired, whereas it apparently needs to ask the server if its cached copy is still valid.

Tinister
+1  A: 

@Tinister: Well actually what you do is to deal with Conditional GET That is - when a Get request does go from client to server, asking "do you have anything newer than X" and the server say 304 if not. you do avoid the Server generating the js, and the traffic of the js content, however the cost of the request (that is - sending an http request from browser to server) is still there. this stuff is being handled by the Last-Modified/IfMOdifiedThen Headers (one for responses, one for requests) and/or the ETAG header.

Caching is a different thing - that is when the browser decides not to issue the GET request at all. it is being managed by the "Expires" header or the Cache-control header.

you might have a Cache-Control header being setup somewhere and it makes the client disregard the "Expires". Try setting "max-age 3600" or something like it, and see if the request is being cached (forget about FB - instead setup a breakpoint or logging on the server to be sure that it's not being called)

having said that - when dealing with js/css files - you might not want actual caching. that is because if the browser does decide to cache, say for a week, then you cannot force it to reload a new version. so if you deploy a new version to the server, the client won't see it until the week has passed, no matter what the new time (oe etag) of the new resource is - cuz it will never even issue the conditional GET request.

One solution (if you really want to relieve network preassure) is to setup caching for maximum time (say a year), and when the resource changes, you change the URI (as is - add an arbitrary querystring value). this will force the browser to reload the new js resource, and never bother the server again, at least until the next update + next resource URI

Ken Egozi
A: 

I have noticed that atleast firefox seems to utilize "last-modifed" stamp from the initial request when calculating if it even processes a HEAD-request to check for "not-modified" (304) response-code.

Having a really old "last-modified" timestamp seem to cause it to not check for any new versions of the file unless explicitly asked for.

However, I wouldn't heavily rely on that.

jishi