18、Spring MVC 之 HTTP caching support

来源:互联网 发布:网页自动生成软件 编辑:程序博客网 时间:2024/06/06 20:24

一个好的HTTP缓存策略可以显著的提高一个web应用的性能以及客户体验。HTTP响应头'Cache-Control',条件头'Last-Modified'以及'ETag'通常负责这个.

HTTP响应头'Cache-Control'建议私有的cache(e.g. 浏览器),公共的cache(e.g. 代理)它们可以缓存HTTP响应来再次使用。

MVC配置的静态资源,ETag(实体标签)是一个HTTP/1.1允许返回HTTP响应头。web服务可以用它来决定改变一个给定的URL中的内容。它可以被认为是响应头Last-Modified的更加复杂的继承者。当一个服务返回一个Etag头的时候,在If-None-Match头中随后的GETs中客户端可以使用它的header。如果内容并没有改变,服务器会返回304: Not Modified.

注:If-Modified-Since,和Last-Modified一样都是用于记录页面最后修改时间的HTTP 头信息,只是Last-Modified是由服务器往客户端发送的HTTP头,而If-Modified-Since 则是由客户端往服务器发送的头.

这个章节将会描述在Spring Web MVC应用中,选择不同的变量来配置HTTP缓存。

1、Cache-Control HTTP header

Spring Web MVC应用中支持配置”Cache-Conrol”头的多种用法。RFC 7234 Section 5.2.2完整的描述了header以及它对应的指令.有几种方法来解决最常见的情况.

Spring Web MVC使用约定的几个APIs : setCachePeriod(int seconds):
- A -1 value 将会生成一个'Cache-Control'响应头.
- A 0 value 使用 'Cache-Control: no-store'指令禁止缓存.
- An n > 0 value 将会使用'Cache-Control: max-age=n'缓存给定的reponse它n秒.

CacheControl创建类可以通过简单的描述来获取"Cache-Control"指令并且使得很容易的使用它来创建你自己的HTTP缓存策略。一旦创建,CacheControl实例可以接收各个Spring Web MVC APIS当中的参数。

// Cache for an hour - "Cache-Control: max-age=3600"CacheControl ccCacheOneHour = CacheControl.maxAge(1, TimeUnit.HOURS);// Prevent caching - "Cache-Control: no-store"CacheControl ccNoStore = CacheControl.noStore();// Cache for ten days in public and private caches,// public caches should not transform the response// "Cache-Control: max-age=864000, public, no-transform"CacheControl ccCustom = CacheControl.maxAge(10, TimeUnit.DAYS)                                    .noTransform().cachePublic();

2、HTTP caching support for static resources

静态资源可以使用合适的''Cache-Control''和条件header来做到最佳性能。给静态资源配置ResourceHttpRequestHandler可以通过文件metadata和适当的指示不仅可以写入'Last-Modified'头.而且可以写入'Cache-Control'头。

你可以查看ResourceHttpRequestHandler类中的cachePeriod属性或者使用一个CacheControl实例,CacheControl支持更多的特殊的指令。

@Configuration@EnableWebMvcpublic class WebConfig extends WebMvcConfigurerAdapter {    @Override    public void addResourceHandlers(ResourceHandlerRegistry registry) {        registry.addResourceHandler("/resources/**")                .addResourceLocations("/public-resources/")                .setCacheControl(CacheControl.maxAge(1, TimeUnit.HOURS).cachePublic());    }}

And in XML:

<mvc:resources mapping="/resources/**" location="/public-resources/">    <mvc:cache-control max-age="3600" cache-public="true"/></mvc:resources>

3、Support for the Cache-Control, ETag and Last-Modified response headers in Controllers

在Controller中可以支持'Cache-Control', 'ETag', 和/或者 'If-Modified-Since' HTTP requeset,如果response配置设置'Cache-Control'非常推荐使用这种方法.其中包含计算给定请求的long值lastModified 和/或者一个Etag值,把它与请求头'If-Modified-Since'的值并且比较,并且response可能地会返回304状态码(Not Modified).

Controller可以使用HttpEntity类来相互影响request/response.Controller可以返回ResponseEntity用于在response中包含HTTP缓存信息。就像下面一样:

@RequestMapping("/book/{id}")public ResponseEntity<Book> showBook(@PathVariable Long id) {    Book book = findBook(id);    String version = book.getVersion();    return ResponseEntity                .ok()                .cacheControl(CacheControl.maxAge(30, TimeUnit.DAYS))                .eTag(version) // lastModified is also available                .body(book);}

如果像上面这样做不仅会在response头中包含'ETag''Cache-Control',如果response中是一个空的empty body,如果client发送条件头匹配Controller设置的缓存信息,它也会转换response到 HTTP 304 Not Modified.

@RequestMapping方法同样也支持上面的东西.可以使用下面的配置来完成:

@RequestMappingpublic String myHandleMethod(WebRequest webRequest, Model model) {    long lastModified = // 1. application-specific calculation    if (request.checkNotModified(lastModified)) {        // 2. shortcut exit - no further processing necessary        return null;    }    // 3. or otherwise further request processing, actually preparing content    model.addAttribute(...);    return "myViewName";}

这里主要有2个关键原理:叫做request.checkNotModified(lastModified)并且返回 null.这个模型会在它返回true之前设置response状态为304.然后,与前者结合,通知Spring MVC不要去处理request请求。

注意:这种情况下有3个变种:
- request.checkNotModified(lastModified) compares lastModified with the 'If-Modified-Since' request header
- request.checkNotModified(eTag) compares eTag with the 'ETag' request header
- request.checkNotModified(eTag, lastModified) does both, meaning that both conditions should be valid for the server to issue an HTTP 304 Not Modified response

4、Shallow ETag support

Spring通过ShallowEtagHeaderFilter来提供ETags支持。它是一个简单的Servlet Filter,因此可以和其它web框架结合起来使用。ShallowEtagHeaderFilter过滤器创建所谓的shallow ETags(与deep ETags相反)。这个Filter会缓存JSP(or other content)渲染的content,为它生成一个MD5的hash并且在response的header中返回一个ETag.当客户端下次对于同样的资源发送请求的时候,它会使用上面生成的hash作为如果If-None-Match的值。这个Filter会查出它,再次渲染这个页面,并且比较两个hashes.如果它们相等,会返回状态码304.

注意:这个策略会保存网络带宽但不会保存CPU,对于完整的响应必须计算每个请求.其它策略是在controller层可以保存网络带宽并且可以避免.mvc-config-static-resources.

你可以在web.xml配置ShallowEtagHeaderFilter:

<filter>    <filter-name>etagFilter</filter-name>    <filter-class>org.springframework.web.filter.ShallowEtagHeaderFilter</filter-class></filter><filter-mapping>    <filter-name>etagFilter</filter-name>    <servlet-name>petclinic</servlet-name></filter-mapping>

Or in Servlet 3.0+ environments,

public class MyWebAppInitializer extends AbstractDispatcherServletInitializer {    // ...    @Override    protected Filter[] getServletFilters() {        return new Filter[] { new ShallowEtagHeaderFilter() };    }}

因为水平有限,翻译不足之处还望见谅。
原文地址:spring-framework-reference-4.2.6.RELEASE

0 0
原创粉丝点击