The initial situation was simple. When I changed a static file on my webserver (Tomcat 6), this change wasn't reflected in a browser. I thought that with all my knowledge of web applications this should have been an easy one for me, but it turned out that it takes some time to sort things out.
Default servlet
My first suspicion was that Tomcat's default servlet is not checking the modification
time of the resource. Fortunately, this wasn't the case and I found it out by
going through it's code. (Doing that I found out the strange fact that
If-None-Match
HTTP header takes precedence over
Cache-Control
and I suspected this is the problem for a while...)
cachingAllowed attribute
Next, there's cachingAllowed attribute in the container context settings described as
If the value of this flag is true, the cache for static resources will be used. If not specified, the default value of the flag is true.
My second suspicion was that Tomcat is caching it's static resources (and therefore sending back 304 Not Modified status), but it wasn't the case again. Tomcat caching is either checking the file modification time (and reloads the cache) or the cache time is too short to be the cause. I don't know exactly because I didn't dig deeper - several tests with http headers dumper was enough for me and led me to the final solution.
HTTP caching directives
The final one to blame is
Cache-Control
HTTP header.
Tomcat's default servlet didn't send this header so that caching algorithms
could be used along the request/response chain, which means even in the browser itself.
This results in a situation where browser is not even asking server for some of the resources. There's emphasis on those words, because for example the caching algorithm behavior in Firefox is unpredictable according to my HTTP headers dump (Which confused me so much that I didn't think about this possibility earlier). I think this caching algorithm is somehow based on number of changes to the resource in the past, but again, I don't care.
Solution
The abstract solution is simple. Server must send
Cache-Control: no-cache
HTTP header with static resources
that is changed often. The bad thing is that I haven't found any settings
concerning this in any configuration documentation. It has to be done manually
with filters.
Although it should be a simple and straightforward filter, it's better
to use something already done. I found such a
simple headers filter. It's
transparent and open-sourced so that you can check it manually and prepare your
own build (don't you ever dare to put binaries on your server from
an unknown source). And now my web.xml
settings looks like this:
httpHeaders org.ft.servlet.filters.httpheaders.HTTPHeadersFilter Cache-Control no-cache Pragma no-cache negativeMapping .*\.xsl|.*\.js|.*\.css ]]> httpHeaders /v2/*
Doesn't look like a five minute job any more, heh?