# 1.8 HTTP Caching

HTTP缓存可以显着提高Web应用程序的性能。 HTTP缓存围绕Cache-Control响应标头以及随后的条件请求标头（例如Last-Modified和ETag）。 缓存控制为私有（例如浏览器）和公共（例如代理）缓存提供有关如何缓存和重用响应的建议。 ETag标头用于发出条件请求，如果内容未更改，则可能导致没有主体的304（NOT\_MODIFIED）。 ETag可以看作是Last-Modified头的更复杂的后继者。

本节描述了Spring Web MVC中与HTTP缓存相关的选项。

## 1.8.1 CacheControl

CacheControl支持配置与Cache-Control标头相关的设置，并在许多地方作为参数被接受：

* WebContentInterceptor
* WebContentGenerator
* 控制器
* 静态资源

尽管RFC 7234描述了Cache-Control响应标头的所有可能的指令，但CacheControl类型采用了面向用例的方法，着重于常见方案：

```java
// 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();
```

WebContentGenerator还接受一个更简单的cachePeriod属性（以秒为单位定义），该属性的工作方式如下：

* -1值不会生成Cache-Control响应标头。
* 值为0可以防止使用“ Cache-Control：无存储”指令进行缓存。
* n> 0值通过使用'Cache-Control：max-age = n'指令将给定响应缓存n秒。

## 1.8.2 控制器

控制器可以添加对HTTP缓存的显式支持。 我们建议您这样做，因为需要先计算资源的lastModified或ETag值，然后才能将其与条件请求标头进行比较。 控制器可以将ETag标头和Cache-Control设置添加到ResponseEntity，如以下示例所示：

```java
@GetMapping("/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);
}
```

如果与条件请求标头的比较表明内容未更改，则前面的示例发送带有空主体的304（NOT\_MODIFIED）响应。 否则，ETag和Cache-Control标头将添加到响应中。

您还可以在控制器中针对条件请求标头进行检查，如以下示例所示：

```java
@RequestMapping
public String myHandleMethod(WebRequest webRequest, Model model) {

    long eTag = ... 

    if (request.checkNotModified(eTag)) {
        return null; 
    }

    model.addAttribute(...); 
    return "myViewName";
}
```

可以使用三种变体来检查针对eTag值，lastModified值或两者的条件请求。 对于有条件的GET和HEAD请求，可以将响应设置为304（NOT\_MODIFIED）。 对于条件POST，PUT和DELETE，您可以将响应设置为409（PRECONDITION\_FAILED），以防止并发修改。

## 1.8.3 Static Resources

您应该将静态资源与Cache-Control和条件响应标头一起提供，以实现最佳性能。 请参阅有关配置静态资源的部分。

## 1.8.4 ETag Filter

您可以使用ShallowEtagHeaderFilter添加从响应内容计算得出的“shallow” eTag值，从而节省带宽，但不节省CPU时间。 请参阅浅ETag。
