HTTP cache headers in Servlets

Asked

Viewed 776 times

16

I would like to know if there are libraries or solutions to treat requests containing headers as Last-Modified, If-Modified-Since, If-Range (for download summary), If-None-Match, Cache-Control, Pragma, etc and produce code responses 304, Etags, Expires, Last-Modified, Content-Range, etc in Servlets.

While I know those headlines cache and download control are more relevant to static resources, I ran into a situation (which I think is quite common) in which the support for these headers increases the performance and reduces an application’s costs.

In my specific case, I’m building an application open-source for creating collages on Facebook with a colleague (follow link if relevant: http://sfcb.7rtc.com). This application is hosted on GAE that imposes limits and charges for external requests.

In our case we encode a Servlet that acts as a Proxy and Facebook image resizer (link: Proxyservlet). The proxy is necessary to circumvent security exceptions when exporting Canvas content related to Policy of the same origin since Facebook’s static resource servers do not implement headers CORS.

In this case the proxy could simply delegate the headers of request from Servlet to Facebook:

public static final ImmutableSet<String> excludedHeaders = 
    ImmutableSet.of("Cookie", "Host");

protected void doGet(HttpServletRequest request, HttpServletResponse response) {
    final HttpURLConnection connection;
    try {
       // código para abrir o request
       final Enumeration<String> headerNames = request.getHeaderNames();
       while (headerNames.hasMoreElements()) {
           final String headerName = headerNames.nextElement();
           final String headerValue = request.getHeader(headerName);

           if (!excludedHeaders.contains(headerName)) {
               log.info(headerName + " : " + headerValue);
               connection.setRequestProperty(headerName, headerValue);
           }
       }
    }
    // Restante do código
}

And copy the headers and Facebook response status code back to Servlet.

final int httpCode = connection.getResponseCode();
response.setStatus(httpCode);
for (Map.Entry<String, List<String>> entry : connection.getHeaderFields().entrySet()) {
    final String header = entry.getKey();
    log.info(entry.getKey() + " = " + entry.getValue());
    for (String headerValue : entry.getValue()) {
        response.addHeader(header, headerValue);
    }
}
// Código para tratar o corpo da resposta, e em caso de status 200, redimensioná-la.

This was enough to make the application more responsive and greatly alleviate the amount of requests external (repeated images are curled in the browser and requests consecutive do not hit the Servlet).

However, I do not consider this a complete or generic solution (since it is specific to proxy Rvlets).

In the Stack Overflow in English I found references to Fileservlet bo Balusc that implements quite complete the issue of Servlets for local downloads (its code handles all the headers mentioned "in the nail", in addition to supporting gzip compression).

But I wondered if there is a more generic library or solution to treat this type of problem (for example, with the use of Filters and / or a simplified API to abstract implementation details).

Has anyone ever heard of such a thing? (And if not, does anyone apply to start writing such a thing? D).

  • 2

    Whenever I needed these headers, I did the work on the nail from the HttpServletRequest. As in practice the headers within it are only one Map very simple and each of these headers has simple values and pre-defined (with the exception of Etag which is a little bit more complicated), I think that no one took the trouble to worry about leaving things a little sweeter and more abstract for programmers.

  • Revisiting the issue now, I have seen several different cases and problems related to headers, Cdns and caching. Perhaps due to the many varieties of applications, the specific use they make of the HTTP protocol and the limitations of the Cdns themselves, many people end up implementing customized solutions. For example, Amazon’s Cloud Front does not support GZIP compression on-the-fly of resources stored in S3. The solution is to use a proxy with Nginx to intercept requests.

  • Unfortunately, there are no (or unknown) canonical solutions for caching, especially in Java. So it would be difficult to think of a better generic solution than the one presented in the question. But it is a promising and important topic, with much to be explored, which needs innovation especially in a world where every millisecond is a concern.

1 answer

6


There is the library Java EE Cache Filter, consisting of a set of filters for handling headers.

How filters can be mapped via web.xml, I believe that there should not be much difficulty in its application.

The filter to add the cache is CacheFilter. See an example of use:

<filter>
    <filter-name>imagesCache</filter-name>
    <filter-class>com.samaxes.filter.CacheFilter</filter-class>
    <init-param>
        <param-name>static</param-name>
        <param-value>true</param-value>
    </init-param>
    <init-param>
        <param-name>expirationTime</param-name>
        <param-value>2592000</param-value>
    </init-param>
</filter>

<filter-mapping>
    <filter-name>imagesCache</filter-name>
    <url-pattern>/img/*</url-pattern>
</filter-mapping>

Note: I personally did not perform tests with this library to ascertain the details of its operation. But I believe that the solution using filters is adequate.

On the other hand, depending on the volume of data, it may be necessary to use a more specialized service such as Amazon S3 or Cloudflare. In this scenario, you feed the service with the images and it is responsible for resizing and distributing it quickly, efficiently and with configurable cache.

  • 1

    Hi Luiz, your google mojo is better than my hehehe. When providing static resources, GAE has a treatment specific to them and naturally responds well to distributed requests, serving the archives close to the source of Request (many people use GAE as a kind of Poor man’s CDN). As for the library, it seems to do the basics (expires, cache-control, private cache and public cache) but can serve as a starting point for something more generic! Thank you.

  • @Anthonyaccioly "your google mojo is better than mine" + "Poor man’s CDN"... laughs a lot! Well, I just hope I helped, unfortunately it seems that there is no mature library and open with these features.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.