如何在 Spring Boot 中添加 Cache-Control header 到静态资源?
How to add Cache-Control header to static resource in Spring Boot?
如何在 Spring Boot 中为静态资源添加 Cache-Control
HTTP header?
尝试在应用程序中使用 filter-component,正确写入 header,但 Cache-Control
header 被覆盖。
@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
根据 documentation,共 ResourceHandlerRegistry
。这很容易。 (我现在没有与之相关的代码。)
在配置静态资源的地方添加addResourceHandler
方法,它会return ResourceHandlerRegistration
对象。
在那里你可以使用 setCacheControl method. What you have to do is configure and set a CacheControl 对象。
这是因为 spring 4.2,否则你将不得不像下面那样做。
@Configuration
@EnableWebMvc
@ComponentScan("my.packages.here")
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").setCachePeriod(0);
}
}
发生这种情况是因为 Spring 安全性:它重写所有缓存 headers 以完全禁用缓存。
所以我们需要做两件事:
- 禁用spring 静态资源的安全性
- 启用静态资源缓存处理
在当前版本的 Spring 引导中,我们可以在 application.properties 配置中更改此行为。
禁用spring 某些资源的安全性:
# Comma-separated list of paths to exclude from the default secured
security.ignored=/myAssets/**
为静态资源启用发送缓存headers:
# 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 和其他)并重写您的应用程序缓存。
此外,如果某些资源有不使用 content-based 版本的原因 - 您可以使用替代的 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=
Maleenc's,答案正确。但是,此实现存在一个问题。
以下代码将在第一次请求时提供正确的 cache-control header,但以后的请求不会 returns 304 (Not-Modified) return 默认 cache-control header 由 spring 安全设置。
{代码}
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").setCacheControl(CacheControl.maxAge(10, TimeUnit.SECONDS));
}
我已经向 spring 团队提出了这个问题,请参阅 https://jira.spring.io/browse/SPR-15133. Here was there response: "Now you shouldn't disable security cache-control headers for your whole application indeed; the proper way to disable those for a specific path (resource handling, here) is explained in that issue comment, see the "Workaround" section."
使用 spring boot 1.3.3,我使用 malenenc answer 得到了 404 答案。
我可以通过添加资源位置来更正它:
@Configuration
public class HttpClientConfiguration extends WebMvcConfigurerAdapter {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/**").setCacheControl(CacheControl.maxAge(1, TimeUnit.DAYS))
.addResourceLocations("/");
}
}
这些属性控制资源的默认缓存 headers:
spring.resources.cache.cachecontrol.max-age: 3600
https://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html
在spring引导中有很多缓存http资源的方法。使用 spring boot 2.1.1 和 spring security 5.1.1.
1.对于在代码中使用资源处理程序的资源(未测试):
您可以通过这种方式添加资源的自定义扩展。
registry.addResourceHandler
用于添加获取资源的uri路径
.addResourceLocations
用于设置资源在文件系统中的位置(
给出的是类路径的相对路径,但也可以是文件的绝对路径:://。)
.setCacheControl
用于设置缓存headers(不言自明。)
资源链和解析器是可选的(在本例中与默认值完全相同。)
@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。对于使用应用程序属性配置文件的资源
与上面相同,减去特定模式,但现在作为配置。
此配置应用于 static-locations 列出的所有资源。
spring.resources.cache.cachecontrol.no-store=true
spring.resources.cache.cachecontrol.must-revalidate=true
spring.resources.cache.cachecontrol.no-cache=true
3。在控制器级别
这里的Response是作为参数注入到controller方法中的HttpServletResponse
response.setHeader(HttpHeaders.CACHE_CONTROL,
"no-cache, must-revalidate, no-store");
response.setHeader("Expires", "0");
我们还可以在拦截器中添加Cache-Control
header:
@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
我想对使用 @Override public void addResourceHandlers(ResourceHandlerRegistry registry) {}
的给定答案添加一些有用的评论,因为我遇到了一些问题。它们也可能对其他人有用。
假设以下默认目录结构 Spring Boot 2.4 应用程序与 Spring Web MVC。
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());
}
}
如何在 Spring Boot 中为静态资源添加 Cache-Control
HTTP header?
尝试在应用程序中使用 filter-component,正确写入 header,但 Cache-Control
header 被覆盖。
@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
根据 documentation,共 ResourceHandlerRegistry
。这很容易。 (我现在没有与之相关的代码。)
在配置静态资源的地方添加addResourceHandler
方法,它会return ResourceHandlerRegistration
对象。
在那里你可以使用 setCacheControl method. What you have to do is configure and set a CacheControl 对象。
这是因为 spring 4.2,否则你将不得不像下面那样做。
@Configuration
@EnableWebMvc
@ComponentScan("my.packages.here")
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").setCachePeriod(0);
}
}
发生这种情况是因为 Spring 安全性:它重写所有缓存 headers 以完全禁用缓存。 所以我们需要做两件事:
- 禁用spring 静态资源的安全性
- 启用静态资源缓存处理
在当前版本的 Spring 引导中,我们可以在 application.properties 配置中更改此行为。
禁用spring 某些资源的安全性:
# Comma-separated list of paths to exclude from the default secured
security.ignored=/myAssets/**
为静态资源启用发送缓存headers:
# 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 和其他)并重写您的应用程序缓存。
此外,如果某些资源有不使用 content-based 版本的原因 - 您可以使用替代的 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=
Maleenc's,答案正确。但是,此实现存在一个问题。
以下代码将在第一次请求时提供正确的 cache-control header,但以后的请求不会 returns 304 (Not-Modified) return 默认 cache-control header 由 spring 安全设置。 {代码}
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").setCacheControl(CacheControl.maxAge(10, TimeUnit.SECONDS));
}
我已经向 spring 团队提出了这个问题,请参阅 https://jira.spring.io/browse/SPR-15133. Here was there response: "Now you shouldn't disable security cache-control headers for your whole application indeed; the proper way to disable those for a specific path (resource handling, here) is explained in that issue comment, see the "Workaround" section."
使用 spring boot 1.3.3,我使用 malenenc answer 得到了 404 答案。 我可以通过添加资源位置来更正它:
@Configuration
public class HttpClientConfiguration extends WebMvcConfigurerAdapter {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/**").setCacheControl(CacheControl.maxAge(1, TimeUnit.DAYS))
.addResourceLocations("/");
}
}
这些属性控制资源的默认缓存 headers:
spring.resources.cache.cachecontrol.max-age: 3600
https://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html
在spring引导中有很多缓存http资源的方法。使用 spring boot 2.1.1 和 spring security 5.1.1.
1.对于在代码中使用资源处理程序的资源(未测试):
您可以通过这种方式添加资源的自定义扩展。
registry.addResourceHandler
用于添加获取资源的uri路径
.addResourceLocations
用于设置资源在文件系统中的位置( 给出的是类路径的相对路径,但也可以是文件的绝对路径:://。)
.setCacheControl
用于设置缓存headers(不言自明。)
资源链和解析器是可选的(在本例中与默认值完全相同。)
@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。对于使用应用程序属性配置文件的资源
与上面相同,减去特定模式,但现在作为配置。 此配置应用于 static-locations 列出的所有资源。
spring.resources.cache.cachecontrol.no-store=true
spring.resources.cache.cachecontrol.must-revalidate=true
spring.resources.cache.cachecontrol.no-cache=true
3。在控制器级别
这里的Response是作为参数注入到controller方法中的HttpServletResponse
response.setHeader(HttpHeaders.CACHE_CONTROL,
"no-cache, must-revalidate, no-store");
response.setHeader("Expires", "0");
我们还可以在拦截器中添加Cache-Control
header:
@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
我想对使用 @Override public void addResourceHandlers(ResourceHandlerRegistry registry) {}
的给定答案添加一些有用的评论,因为我遇到了一些问题。它们也可能对其他人有用。
假设以下默认目录结构 Spring Boot 2.4 应用程序与 Spring Web MVC。
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());
}
}