在Dropwizard中设置静态资源的缓存控制头

7
4个回答

10

如果有人感兴趣(根据这个问题所拥有的观看数量,他们可能不太感兴趣),这是我如何解决这个问题的。

我在与我的 Service 类相同的包中创建了一个 CacheControlFilter 类:

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 {}
}

然后在服务类中,只需添加以下代码:

env.addFilter(new CacheControlFilter(), "/*");
当然,你可以更细致地添加不同的筛选器,例如针对图像文件和CSS文件的筛选器,但是这会为所有请求添加标题。
从评论中:
对于Dropwizard 1.0.6,只需注册。
env.servlets()
   .addFilter("MyFilter", new CacheControlFilter())
   .addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), true, "/*") 

4
谢谢您,这对我很有帮助。但是需要注意的是,该过滤器按照原样(和安装)适用于每种请求的所有内容(GET,PUT等),而不仅仅适用于静态内容的提供。 - Lambart
1
截至1.0.6版本,以下代码可正常工作。只需注册:env.servlets().addFilter("MyFilter", CacheControlFilter()).addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), true, "/*") - charlie_pl

2
如果您只想清除每个请求的缓存,以下是我的解决方案,它使用DropWizard提供的CacheBustingFilter。请保留HTML标签。
  1. Define a custom Configuration, in my case its WebConfiguration. Use this configuration while setting up your DropWizard Application.

    public class WebConfiguration extends Configuration {
    
    @JsonProperty
    private String enableCacheControl;
    
    public String getEnableCacheControl() {
        return enableCacheControl;
    }
    
    public void setEnableCacheControl(String enableCacheControl) {
        this.enableCacheControl = enableCacheControl;
    }
    

    }

  2. Get the configuration you defined in #1 and register the CacheBustingFilter based on its value.

在你的run方法中添加以下内容 -
    // get the cache control settings from the YAML - configuration
    String enableCacheControl = configuration.getEnableCacheControl();
    boolean enableCacheBustingFilter = Boolean.parseBoolean(enableCacheControl);

    if(enableCacheBustingFilter){
        // caching was enabled in YAML - was set to true - enabling the cacheBustingFilter
        // this will ALWAYS return  "must-revalidate,no-cache,no-store" in the Cache-Control response header
        environment.servlets().addFilter("CacheBustingFilter", new CacheBustingFilter())
            .addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), true, "/*");
    }

谢谢,这个有效!我漏掉了“addMappingForUrlPatterns”,没有它这个程序会默默无闻 :-( - Rich

2

基于Tim Barclay的答案,我创建了一个过滤器。如果所请求的资源是使用js、css、png、jpg、gif或svg扩展名的文件,则该过滤器会将Cache-Control和Expires设置为一年后,并禁用缓存。

希望对某些人有所帮助!

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:我无法使用已接受答案的方法来设置Expires头文件:

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

我的版本相比之下非常臃肿,但它可以工作:
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()));

根据@Rich在我的回答中的评论,看起来我建议的方法可能已经无法在当前版本的Dropwizard中使用了。实际上,自2014年以来我就没有使用过它(或者Java)。因此我无法验证。 - Tim Barclay

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接