[英]How to enable HTTP response caching in Spring Boot
我已经使用 Spring Boot 1.0.2 实现了一个 REST 服务器。 我无法阻止 Spring 设置禁用 HTTP 缓存的 HTTP 标头。
我的控制器如下:
@Controller
public class MyRestController {
@RequestMapping(value = "/someUrl", method = RequestMethod.GET)
public @ResponseBody ResponseEntity<String> myMethod(
HttpServletResponse httpResponse) throws SQLException {
return new ResponseEntity<String>("{}", HttpStatus.OK);
}
}
所有 HTTP 响应都包含以下标头:
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Expires: 0
Pragma: no-cache
我尝试了以下方法来删除或更改这些标题:
setCacheSeconds(-1)
。httpResponse.setHeader("Cache-Control", "max-age=123")
。WebContentInterceptor
@Bean
,我为其调用了setCacheSeconds(-1)
。spring.resources.cache-period
设置为 -1 或application.properties
的正值。以上都没有任何影响。 如何在 Spring Boot 中为所有或单个请求禁用或更改这些标头?
结果证明无缓存 HTTP 标头是由 Spring Security 设置的。 这在http://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#headers 中进行了讨论。
以下内容禁用 HTTP 响应标头Pragma: no-cache
,但不能以其他方式解决问题:
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.servlet.configuration.EnableWebMvcSecurity;
@Configuration
@EnableWebMvcSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// Prevent the HTTP response header of "Pragma: no-cache".
http.headers().cacheControl().disable();
}
}
我最终为公共静态资源完全禁用了 Spring Security,如下所示(在与上面相同的类中):
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/static/public/**");
}
这需要配置两个资源处理程序以正确获取缓存控制标头:
@Configuration
public class MvcConfigurer extends WebMvcConfigurerAdapter
implements EmbeddedServletContainerCustomizer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
// Resources without Spring Security. No cache control response headers.
registry.addResourceHandler("/static/public/**")
.addResourceLocations("classpath:/static/public/");
// Resources controlled by Spring Security, which
// adds "Cache-Control: must-revalidate".
registry.addResourceHandler("/static/**")
.addResourceLocations("classpath:/static/")
.setCachePeriod(3600*24);
}
}
Spring Boot 中有很多方法可以用于 http 缓存。 使用 spring boot 2.1.1 和额外的 spring security 5.1.1。
1.对于在代码中使用resourcehandler的资源:
您可以通过这种方式添加资源的自定义扩展。
registry.addResourceHandler
用于添加获取资源的uri路径
.addResourceLocations
用于在文件系统中设置资源所在的位置(给定的是类路径的相对路径,但文件的绝对路径::// 也是可能的。)
.setCacheControl
用于设置缓存头(不言自明。)
Resourcechain 和 resolver 是可选的(在这种情况下与默认值完全相同。)
@Configuration
public class CustomWebMVCConfig implements WebMvcConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/*.js", "/*.css", "/*.ttf", "/*.woff", "/*.woff2", "/*.eot",
"/*.svg")
.addResourceLocations("classpath:/static/")
.setCacheControl(CacheControl.maxAge(365, TimeUnit.DAYS)
.cachePrivate()
.mustRevalidate())
.resourceChain(true)
.addResolver(new PathResourceResolver());
}
}
2.对于使用应用程序属性配置文件的资源
与上面相同,减去特定模式,但现在作为配置。 此配置应用于列出的静态位置中的所有资源。
spring.resources.cache.cachecontrol.cache-private=true
spring.resources.cache.cachecontrol.must-revalidate=true
spring.resources.cache.cachecontrol.max-age=31536000
spring.resources.static-locations=classpath:/static/
3. 在控制器层面
这里的Response是作为参数注入到控制器方法中的HttpServletResponse。
no-cache, must-revalidate, private
getHeaderValue 将缓存选项输出为字符串。 例如
response.setHeader(HttpHeaders.CACHE_CONTROL,
CacheControl.noCache()
.cachePrivate()
.mustRevalidate()
.getHeaderValue());
我找到了这个 Spring 扩展: https : //github.com/foo4u/spring-mvc-cache-control 。
你只需要做三个步骤。
第 1 步(pom.xml):
<dependency>
<groupId>net.rossillo.mvc.cache</groupId>
<artifactId>spring-mvc-cache-control</artifactId>
<version>1.1.1-RELEASE</version>
<scope>compile</scope>
</dependency>
第 2 步(WebMvcConfiguration.java):
@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new CacheControlHandlerInterceptor());
}
}
第 3 步(控制器):
@Controller
public class MyRestController {
@CacheControl(maxAge=31556926)
@RequestMapping(value = "/someUrl", method = RequestMethod.GET)
public @ResponseBody ResponseEntity<String> myMethod(
HttpServletResponse httpResponse) throws SQLException {
return new ResponseEntity<String>("{}", HttpStatus.OK);
}
}
可以通过以下方式覆盖特定方法的默认缓存行为:
@Controller
public class MyRestController {
@RequestMapping(value = "/someUrl", method = RequestMethod.GET)
public @ResponseBody ResponseEntity<String> myMethod(
HttpServletResponse httpResponse) throws SQLException {
return new ResponseEntity.ok().cacheControl(CacheControl.maxAge(100, TimeUnit.SECONDS)).body(T)
}
}
CacheControl类是一个流畅的构建器,它使我们可以轻松创建不同类型的缓存:
@GetMapping("/users/{name}")
public ResponseEntity<UserDto> getUser(@PathVariable String name) {
return ResponseEntity.ok()
.cacheControl(CacheControl.maxAge(60, TimeUnit.SECONDS))
.body(new UserDto(name));
}
让我们在测试中点击这个端点,并断言我们已经更改了标头:
given()
.when()
.get(getBaseUrl() + "/users/Michael")
.then()
.header("Cache-Control", "max-age=60");
我遇到了类似的问题。 我只想在浏览器中缓存一些动态资源(图像)。 如果图像更改(不经常),我会更改 uri 的部分...这是我的解决方案
http.headers().cacheControl().disable();
http.headers().addHeaderWriter(new HeaderWriter() {
CacheControlHeadersWriter originalWriter = new CacheControlHeadersWriter();
@Override
public void writeHeaders(HttpServletRequest request, HttpServletResponse response) {
Collection<String> headerNames = response.getHeaderNames();
String requestUri = request.getRequestURI();
if(!requestUri.startsWith("/web/eventImage")) {
originalWriter.writeHeaders(request, response);
} else {
//write header here or do nothing if it was set in the code
}
}
});
@Configuration
@EnableAutoConfiguration
public class WebMvcConfiguration extends WebMvcConfigurerAdapter {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**")
.addResourceLocations("/resources/")
.setCachePeriod(31556926);
}
}
如果您不关心对静态资源进行身份验证,您可以这样做:
import static org.springframework.boot.autoconfigure.security.servlet.PathRequest.toStaticResources;
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
...
@Override
public void configure(WebSecurity webSecurity) throws Exception {
webSecurity
.ignoring()
.requestMatchers(toStaticResources().atCommonLocations());
}
...
}
并在您的application.properties
:
spring.resources.cache.cachecontrol.max-age=43200
有关可以设置的更多属性,请参阅ResourceProperties.java 。
我在控制器中使用了以下几行。
ResponseEntity.ok().cacheControl(CacheControl.maxAge(secondWeWantTobeCached, TimeUnit.SECONDS)).body(objToReturnInResponse);
请注意,响应将具有值为 secondWeWantTobeCached 的标头 Cache-Control。 但是,如果我们在地址栏中输入 url 并按 Enter,请求将始终从 Chrome 发送到服务器。 但是,如果我们从某个链接点击 url,浏览器将不会发送新请求,而是从缓存中获取。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.