Skip to content

HTTP 缓存 (HTTP Caching)

HTTP 缓存可以显著提高 Web 应用的性能。它主要通过 Cache-Control 响应头以及随后的条件请求(如 ETagLast-Modified)来实现。

核心技术

1. CacheControl

Spring 提供了 CacheControl 类来简化 Cache-Control 标头的配置。

java
// 缓存一小时
CacheControl cc = CacheControl.maxAge(1, TimeUnit.HOURS).cachePublic();

// 禁止缓存
CacheControl noCache = CacheControl.noStore();
kotlin
val cc = CacheControl.maxAge(1, TimeUnit.HOURS).cachePublic()
val noCache = CacheControl.noStore()

2. 控制器配置

你可以直接在 ResponseEntity 中设置缓存规则。

java
@GetMapping("/book/{id}")
public ResponseEntity<Book> showBook(@PathVariable Long id) {
    Book book = findBook(id);
    String etag = book.getVersion();

    return ResponseEntity.ok()
            .cacheControl(CacheControl.maxAge(30, TimeUnit.DAYS))
            .eTag(etag) // 也可以使用 lastModified
            .body(book);
}

3. Shallow ETag 过滤器

如果你不想在业务代码中手动管理 ETag,可以注册 ShallowEtagHeaderFilter。它会根据响应内容自动计算 MD5 哈希值。虽然它节省了网络带宽(如果内容没变会返回 304),但并不能节省服务器计算 HTML/JSON 的 CPU 时间。


补充教学

1. 强缓存 vs 协商缓存

  • 强缓存 (max-age):浏览器在过期前直接使用本地备份,不发请求。
  • 协商缓存 (ETag/Last-Modified):浏览器询问服务器“我手里的东西变了吗?”。如果没变(304 Not Modified),服务器返回空包体,节省流量。

2. ETag 的精妙之处

相比于 Last-Modified(只能精确到秒,且文件内容不变但修改时间变了也会失效),ETag 是内容的指纹。 Spring 的做法:Spring 系统地支持了规范中的条件分支。如果是 GET/HEAD 请求且匹配,返回 304;如果是 PUT/DELETE 请求且不匹配,返回 412 (Precondition Failed),有效防止“丢失更新”问题。

3. 静态资源的缓存优化

在 Spring MVC 的资源配置中,务必为静态文件设置长效缓存。配合文件名加哈希值(版本化资源链接)的策略,可以实现“永不过期”的效果,直到你发布新版本。

Based on Spring Framework.