如何在Spring Boot中将Cache-Control标头添加到静态资源?

时间:2015-10-19 12:32:58

标签: java spring-boot cache-control

如何在Spring Boot中为静态资源添加Cache-Control HTTP标头?

尝试在应用程序中使用过滤器组件,该组件正确地写入标头,但Cache-Control标头被覆盖。

@Component
public class CacheBustingFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) 
                                              throws IOException, ServletException {

        HttpServletResponse httpResp = (HttpServletResponse) resp;
        httpResp.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
        httpResp.setHeader("This-Header-Is-Set", "no-cache, no-store, must-revalidate");
        httpResp.setHeader("Expires", "0");

        chain.doFilter(req, resp);
    }

我在浏览器中获得的是:

Cache-Control:no-store
This-Header-Is-Set:no-cache, no-store, must-revalidate
Expires:0

我想要的是:

Cache-Control:no-cache, no-store, must-revalidate
This-Header-Is-Set:no-cache, no-store, must-revalidate
Expires:0

8 个答案:

答案 0 :(得分:13)

这是因为Spring Security:它会重写所有缓存标头以完全禁用缓存。 所以我们需要做两件事:

  1. 禁用静态资源的弹簧安全性
  2. 启用静态资源缓存处理
  3. 在当前版本的Spring Boot中,我们可以在application.properties config中更改此行为。

    禁用某些资源的spring security:

    # Comma-separated list of paths to exclude from the default secured 
    security.ignored=/myAssets/**
    

    启用静态资源的缓存标头:

    # Enable HTML5 application cache manifest rewriting.
    spring.resources.chain.html-application-cache=true
    
    # Enable the Spring Resource Handling chain. Disabled by default unless at least one strategy has been enabled.
    spring.resources.chain.enabled=true
    # Enable the content Version Strategy.
    spring.resources.chain.strategy.content.enabled=true 
    # Comma-separated list of patterns to apply to the Version Strategy.
    spring.resources.chain.strategy.content.paths=/** 
    
    # Locations of static resources.
    spring.resources.static-locations=classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/,classpath:/public/
    

    这就是全部。现在,Spring将检查您的静态文件是否已更改,并且可以发送更智能的响应(If-Modiffied-Since和其他)并重写您的appcache。

    此外,如果有理由不对某些资源使用基于内容的版本 - 您可以使用备用FixedVersion策略并在配置中明确设置版本:

    #Enable the fixed Version Strategy.
    spring.resources.chain.strategy.fixed.enabled=false 
    # Comma-separated list of patterns to apply to the Version Strategy.
    spring.resources.chain.strategy.fixed.paths= 
    # Version string to use for the Version Strategy.
    spring.resources.chain.strategy.fixed.version= 
    

    See more in docs

答案 1 :(得分:12)

根据ResourceHandlerRegistry addResourceHandler。这很容易。 (我现在没有相关的代码。)

在配置静态资源的地方,只需添加ResourceHandlerRegistration方法,它将返回@Configuration @EnableWebMvc @ComponentScan("my.packages.here") public class WebConfig extends WebMvcConfigurerAdapter { @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/resources/**").setCachePeriod(0); } } 个对象。

您可以使用documentation方法。您需要做的是配置和设置setCacheControl obejct。

这是自4.2春季以来,否则你将不得不这样做。

php composer.phar install

答案 2 :(得分:2)

以下属性可控制资源的默认缓存头:

spring.resources.cache.cachecontrol.max-age: 3600

https://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html

答案 3 :(得分:1)

Maleenc's,答案是对的。但是,此实现存在一个问题。

以下代码将在第一个请求中提供正确的缓存控制头,但返回304(未修改)的未来请求将返回spring security设置的默认缓存控制头。 {code}

public void addResourceHandlers(ResourceHandlerRegistry registry) {         
    registry.addResourceHandler("/resources/**").setCacheControl(CacheControl.maxAge(10, TimeUnit.SECONDS));
}

我已将此问题提交给春季团队,请参阅https://jira.spring.io/browse/SPR-15133。这里有响应:“现在你不应该为你的整个应用程序禁用安全缓存控制头;在该问题注释中解释了为特定路径(资源处理,这里)禁用那些头文件的正确方法,请参阅{{ 3}}

答案 4 :(得分:1)

使用spring boot 1.3.3,我使用maleenc回答得到了404回答。 我可以通过添加资源位置来纠正它:

{{1}}

答案 5 :(得分:1)

spring boot中有很多方法可以缓存http资源。使用Spring Boot 2.1.1和额外的Spring Security 5.1.1。

1。对于在代码中使用resourcehandler的资源(未测试):

您可以通过这种方式添加自定义资源扩展。

registry.addResourceHandler

用于将uri路径添加到获取资源的位置

.addResourceLocations

用于设置文件系统中资源所在的位置( 给出的是具有classpath的相对路径,但也可以使用file :: //的绝对路径。)

.setCacheControl

用于设置缓存头(说明)。

Resourcechain和resolver是可选的(在这种情况下,与默认值完全相同)。

@Configuration
public class CustomWebMVCConfig implements WebMvcConfigurer {

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
    registry.addResourceHandler("/**")
            .addResourceLocations("classpath:/static/")
            .setCacheControl(CacheControl.noStore()
                    .mustRevalidate())
            .setCacheControl(CacheControl.noCache())
            .resourceChain(true)
            .addResolver(new PathResourceResolver());
    }
}

2。对于使用应用程序属性配置文件的资源

与上面相同,减去了特定的模式,但现在是config。 此配置将应用于列出的静态位置中的所有资源。

spring.resources.cache.cachecontrol.no-store=true
spring.resources.cache.cachecontrol.must-revalidate=true
spring.resources.cache.cachecontrol.no-cache=true

3。在控制器级别

这里的响应是作为参数注入到控制器方法中的HttpServletResponse。

response.setHeader(HttpHeaders.CACHE_CONTROL,
            "no-cache, must-revalidate, no-store");
response.setHeader("Expires", "0");

答案 6 :(得分:0)

我们还可以在拦截器中添加Cache-Control头:

@Override
public void addInterceptors(InterceptorRegistry registry) {
    WebContentInterceptor interceptor = new WebContentInterceptor();
    interceptor.addCacheMapping(CacheControl.maxAge(60, TimeUnit.SECONDS)
      .noTransform()
      .mustRevalidate(), "/static/**");
    registry.addInterceptor(interceptor);
}

那么我们不必指定资源位置。

https://www.baeldung.com/spring-mvc-cache-headers#cache-interceptors

答案 7 :(得分:0)

我想为使用 @Override public void addResourceHandlers(ResourceHandlerRegistry registry) {} 的给定答案添加一些有用的评论,因为我遇到了一些问题。它们可能对其他人也有用。

假设具有 Spring Web MVC 的默认 Spring Boot 2.4 应用程序的目录结构如下。

src/main/resources/
|- static/
  |- res/
    |- css/
    |- js/
  |- images/
  |- favicon.ico

我们想为 css、js、图像和网站图标添加缓存。然后配置看起来像这样:

import org.springframework.boot.autoconfigure.web.WebProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.CacheControl;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.util.concurrent.TimeUnit;

@Configuration
public class CacheStaticResourcesConfiguration implements WebMvcConfigurer {

    /**
     * We provide a custom configuration which resolves URL-Requests to static files in the
     * classpath (src/main/resources directory).
     *
     * This overloads a default configuration retrieved at least partly from
     * {@link WebProperties.Resources#getStaticLocations()}.
     * @param registry ResourceHandlerRegistry
     */
    @Override
    public void addResourceHandlers(final ResourceHandlerRegistry registry) {
        /*
         * BE AWARE HERE:
         *
         * .addResourceHandler(): URL Paths
         * .addResourceLocations(): Paths in Classpath to look for file
         *   root "/" refers to src/main/resources
         *   For configuration example, see:
         *     org.springframework.boot.autoconfigure.web.WebProperties.Resources().getStaticLocations()
         *
         * .addResourceLocations("classpath:/static/")
         *   =>
         *      addResourceHandler("/**")
         *      => GET /res/css/main.css
         *         => resolved as: "classpath:/static/res/css/main.css"
         *      BUT
         *      addResourceHandler("/res/**")
         *      => GET /res/css/main.css
         *            (spring only appends the ** to the value from
         *             addResourceLocations())
         *         => resolved as: "classpath:/static/css/main.css"
         */

        registry
                .addResourceHandler("/favicon.ico")
                .addResourceLocations("classpath:/static/")
                .setCacheControl(CacheControl.maxAge(1, TimeUnit.DAYS)
                        .noTransform()
                        .mustRevalidate());

        registry
                .addResourceHandler("/res/**")
                // trailing slash is important!
                .addResourceLocations("classpath:/static/res/")
                .setCacheControl(CacheControl.maxAge(7, TimeUnit.DAYS)
                        .noTransform()
                        .mustRevalidate());

        registry
                .addResourceHandler("/images/**")
                // trailing slash is important!
                .addResourceLocations("classpath:/static/images/")
                .setCacheControl(CacheControl.maxAge(7, TimeUnit.DAYS)
                        .noTransform()
                        .mustRevalidate());
    }

}