Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Set cache control headers of static assets in Dropwizard

What's the best way to set the cache control headers of static assets in a Dropwizard service?

Some Googling showed up an AssetsBundle constructor:

AssetsBundle(String resourcePath, com.google.common.cache.CacheBuilderSpec cacheBuilderSpec, String uriPath)

However on further investigation, it looks like the package com.yammer.dropwizard.bundles hasn't been part of Dropwizard since version 5.1.

Perhaps I'm missing something obvious, but is there a preferred way to handle this?

like image 757
Tim Barclay Avatar asked Nov 18 '13 16:11

Tim Barclay


People also ask

How do I add a cache-control header?

If you want to enable Cache-Control for all files, add Header set line outside the filesMatch block. As you can see, we set the Cache-Control header's max-age to 3600 seconds and to public for the listed files.

What do cache-control headers do?

What is the Cache-Control Header. Cache-control is an HTTP header used to specify browser caching policies in both client requests and server responses. Policies include how a resource is cached, where it's cached and its maximum age before expiring (i.e., time to live).

What is the default value of cache-control?

cache_control property sets the default Cache-Control value in HTTP response headers to private or public. The default is private. Static content can be cached at the browser (client) level, but not at the proxy server level.


2 Answers

In case anyone is interested (which, judging by the number of views this question has had, they probably aren't) this is how I solved this.

I created a CacheControlFilter class in the same package as my Service class:

public class CacheControlFilter implements Filter{

    public void doFilter(ServletRequest request, ServletResponse response,
        FilterChain chain) throws IOException, ServletException {

        HttpServletResponse resp = (HttpServletResponse) response;

        // Add whatever headers you want here
        resp.setHeader("Cache-Control", "public, max-age=500000");
        resp.setHeader("Expires", new Date().getTime()+500000 + "");

        chain.doFilter(request, response);
    }

    public void destroy() {}

    public void init(FilterConfig arg0) throws ServletException {}
}

Then in the service class, just add the line:

env.addFilter(new CacheControlFilter(), "/*");

Of course you could be more finegrained and add a different filter for, say, image files and css files but this adds the headers for all requests.

From Comments :

for dropwizard 1.0.6. Just register with

env.servlets()
   .addFilter("MyFilter", new CacheControlFilter())
   .addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), true, "/*") 
like image 163
Tim Barclay Avatar answered Nov 09 '22 18:11

Tim Barclay


Building on the answer from Tim Barclay, I created a filter which sets Cache-Control and Expires one year into the future, if the resource requested is a file with extension js, css, png, jpg, gif or svg. Otherwise the cache is disabled.

Hope it can be helpful for someone!

protected void setCacheHeaders(Environment environment, String urlPattern, int seconds) {
    FilterRegistration.Dynamic filter = environment.servlets().addFilter(
            "cacheControlFilter",
            new Filter() {
                @Override
                public void init(FilterConfig filterConfig) throws ServletException {

                }

                @Override
                public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

                    HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
                    HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse;

                    String[] cacheFileTypes = {"js","css","png","jpg","gif","svg"};
                    String filetypeRequested = FilenameUtils.getExtension(httpServletRequest.getRequestURL().toString());

                    if (httpServletRequest.getMethod() == "GET" && seconds > 0 && Arrays.asList(cacheFileTypes).contains(filetypeRequested)) {
                        httpServletResponse.setHeader("Cache-Control", "public, max-age=" + seconds);
                        Calendar c = Calendar.getInstance();
                        c.setTime(new Date());
                        c.add(Calendar.SECOND, seconds);
                        SimpleDateFormat format = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss zzz", Locale.US);
                        format.setTimeZone(TimeZone.getTimeZone("GMT"));
                        httpServletResponse.setHeader("Expires", format.format(c.getTime()));
                    } else {
                        httpServletResponse.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
                        httpServletResponse.setHeader("Expires", "0");
                        httpServletResponse.setHeader("Pragma", "no-cache");
                    }

                    filterChain.doFilter(servletRequest, servletResponse);

                }

                @Override
                public void destroy() {

                }
            }
    );
    filter.addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class), true, urlPattern);
}

PS: I couldn't get the accepted answer's way to set the Expires-header to work:

resp.setHeader("Expires", new Date().getTime()+500000 + "");

Mine is terribly bloated in comparison, but it works:

Calendar c = Calendar.getInstance();
c.setTime(new Date());
c.add(Calendar.SECOND, seconds);
SimpleDateFormat format = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss zzz", Locale.US);
format.setTimeZone(TimeZone.getTimeZone("GMT"));
httpServletResponse.setHeader("Expires", format.format(c.getTime()));
like image 41
Terje Andersen Avatar answered Nov 09 '22 20:11

Terje Andersen