0
votes

In order to optimize caching, I added timestamps to the src values of images, etc, e.g. <img src="/static/img/foo.1456871418309.png"/>.

Then I created a servlet filter which removes the timestamps again, and then forwards the request to the resource. request.getRequestDispatcher (urlWithoutTimestamp).forward(request, response).

And in appengine-web.xml I specified to cache files a year.

<static-files>
    <include path="/static/**" expiration="365d" />
</static-files>

This way, I thought, the user would always get the latest version and can cache it until a newer version exists, without having to test it via HTTP.

On localhost (Run As Web Application) this works fine, the HTTP response has the expected caching headers:

Cache-Control:"public, max-age=31536000"
Expires:"Wed, 01 Mar 2017 22:54:32 GMT"

However when I deploy the whole thing on the app engine server the response has this caching header (and no “Expires”):

Cache-Control:"private"

Instead of forwarding the request, I also tried calling the FilterChain on a HttpServletRequestWrapper to modify the getRequestURI, getRequestURL, getServletPath. This lead to the same poor result.

How do I get this right?

Update:

On second thought, I guess forwarding to static-content may not be possible, because forwarding is always done server locally and the static-content may well be served on another machine.

But at least I was able to solve my HTTP header problem with my filter:

  1. Instead of forwarding the request, I use a HttpServletRequestWrapper (see above) to remove the timestamp from the request.
  2. Then I call chain.doFilter on the modified request.
  3. Last I set the caching headers on the response.
2

2 Answers

1
votes

Instead of changing filename and using a filter you can reference actual static file with timestamp added as request parameter.

Instead of:

<img src="/static/img/foo.1456871418309.png"/>

use following schema:

<img src="/static/img/foo.png?r=1456871418309"/>

For static file such parameters are ignored. But for browser it will be a new URL each time, therefore it will be requested from the server.

1
votes

In production, you will not be able to intercept static file traffic. Google App Engine takes care of static files for you, basically providing a sort of CDN.

I quote the note on https://cloud.google.com/appengine/docs/java/config/webxml#Filters

Filters are not invoked on static assets, even if the path matches a filter-mapping pattern. Static files are served directly to the browser.