1.9. HTTP 缓存

预计阅读时间: 6 分钟

HTTP caching can significantly improve the performance of a web application. HTTP caching revolves around the Cache-Control response header and, subsequently, conditional request headers (such as Last-Modified and ETag). Cache-Control advises private (for example, browser) and public (for example, proxy) caches on how to cache and re-use responses. An ETag header is used to make a conditional request that may result in a 304 (NOT_MODIFIED) without a body, if the content has not changed. ETag can be seen as a more sophisticated successor to the Last-Modified header.
HTTP 缓存可以显著提高 Web 应用程序的性能。HTTP 缓存围绕 Cache-Control 响应头展开,随后是条件请求头(例如 Last-ModifiedETag )。 Cache-Control 建议私有(例如,浏览器)和公共(例如,代理)缓存如何缓存和重用响应。用于发起可能返回 304(NOT_MODIFIED)状态码且无响应体的条件请求的 ETag 头。 ETag 可以看作是 Last-Modified 头的更高级的继承者。

This section describes the HTTP caching-related options that are available in Spring Web MVC.
本节描述了 Spring Web MVC 中可用的与 HTTP 缓存相关的选项。

(#mvc-caching-cachecontrol)1.9.1.CacheControl

CacheControl provides support for configuring settings related to the Cache-Control header and is accepted as an argument in a number of places:
CacheControl 提供了对与 Cache-Control 标头相关的设置进行配置的支持,并在多个地方作为参数被接受:

While RFC 7234 describes all possible directives for the Cache-Control response header, the CacheControl type takes a use case-oriented approach that focuses on the common scenarios:
尽管 RFC 7234 描述了所有可能的响应头指令,但 CacheControl 类型采用以用例为导向的方法,重点关注常见场景:

// 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();
// Cache for an hour - "Cache-Control: max-age=3600" val ccCacheOneHour = CacheControl.maxAge(1, TimeUnit.HOURS) // Prevent caching - "Cache-Control: no-store" val 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" val ccCustom = CacheControl.maxAge(10, TimeUnit.DAYS).noTransform().cachePublic()

WebContentGenerator also accepts a simpler cachePeriod property (defined in seconds) that works as follows:
WebContentGenerator 还接受一个更简单的 cachePeriod 属性(以秒为单位),其工作方式如下:

  • A -1 value does not generate a Cache-Control response header.
    一个 -1 值不会生成一个 Cache-Control 响应头。

  • A 0 value prevents caching by using the 'Cache-Control: no-store' directive.
    一个 0 值通过使用 'Cache-Control: no-store' 指令来防止缓存。

  • An n > 0 value caches the given response for n seconds by using the 'Cache-Control: max-age=n' directive.
    一个 n > 0 值通过使用 'Cache-Control: max-age=n' 指令缓存给定响应 n 秒。

(#mvc-caching-etag-lastmodified)1.9.2. Controllers 1.9.2. 控制器

Controllers can add explicit support for HTTP caching. We recommended doing so, since the lastModified or ETag value for a resource needs to be calculated before it can be compared against conditional request headers. A controller can add an ETag header and Cache-Control settings to a ResponseEntity, as the following example shows:
控制器可以添加对 HTTP 缓存的显式支持。我们建议这样做,因为资源在可以与条件请求头进行比较之前,需要计算其 lastModifiedETag 值。控制器可以向一个 ResponseEntity 添加一个 ETag 头和 Cache-Control 设置,如下例所示:

@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); }

1

Application-specific calculation.
应用特定计算。

2

The response has been set to 304 (NOT_MODIFIED)— no further processing.
响应已设置为 304(NOT_MODIFIED)—不再进行进一步处理。

3

Continue with the request processing.
继续处理请求。

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

The preceding example sends a 304 (NOT_MODIFIED) response with an empty body if the comparison to the conditional request headers indicates that the content has not changed. Otherwise, the ETag and Cache-Control headers are added to the response.
前一个示例在比较条件请求头时,如果内容没有变化,则发送一个 304(NOT_MODIFIED)响应,响应体为空。否则,将 ETagCache-Control 头添加到响应中。

You can also make the check against conditional request headers in the controller, as the following example shows:
您还可以在控制器中对条件请求头进行检查,如下例所示:

@RequestMapping public String myHandleMethod(WebRequest request, Model model) { long eTag = ... (1) if (request.checkNotModified(eTag)) { return null; (2) } model.addAttribute(...); (3) return "myViewName"; }

1

Application-specific calculation.
应用特定计算。

2

The response has been set to 304 (NOT_MODIFIED)— no further processing.
响应已设置为 304(NOT_MODIFIED)—不再进行进一步处理。

3

Continue with the request processing.
继续处理请求。

@RequestMapping fun myHandleMethod(request: WebRequest, model: Model): String? { val eTag: Long = ... (1) if (request.checkNotModified(eTag)) { return null (2) } model[...] = ... (3) return "myViewName" }

There are three variants for checking conditional requests against eTag values, lastModified values, or both. For conditional GET and HEAD requests, you can set the response to 304 (NOT_MODIFIED). For conditional POST, PUT, and DELETE, you can instead set the response to 412 (PRECONDITION_FAILED), to prevent concurrent modification.
存在三种针对 eTag 值、 lastModified 值或两者都进行检查的变体。对于条件 GETHEAD 请求,您可以设置响应为 304(NOT_MODIFIED)。对于条件 POSTPUTDELETE ,您可以改为设置响应为 412(PRECONDITION_FAILED),以防止并发修改。

(#mvc-caching-static-resources)1.9.3. Static Resources 1.9.3. 静态资源

You should serve static resources with a Cache-Control and conditional response headers for optimal performance. See the section on configuring Static Resources.
您应该使用 Cache-Control 和条件响应头来提供静态资源以实现最佳性能。请参阅配置静态资源的章节。

(#mvc-httpcaching-shallowetag)1.9.4.ETag Filter 1.9.4.ETag 过滤器

You can use the ShallowEtagHeaderFilter to add “shallow” eTag values that are computed from the response content and, thus, save bandwidth but not CPU time. See Shallow ETag.
您可以使用 ShallowEtagHeaderFilter 来添加从响应内容计算出的“浅层” eTag 值,从而节省带宽但不会消耗 CPU 时间。参见浅层 ETag。