HTTP 缓存技术
1. 缓存概述
HTTP 缓存技术通过存储已请求资源的副本,减少重复请求、提升响应速度,并节省带宽。缓存可以在客户端、代理服务器、CDN(内容分发网络)等位置进行,能够有效提升 Web 应用的性能、降低服务器压力和加速用户访问体验。
2. 缓存的位置和类型
2.1 浏览器缓存(客户端缓存)
- 缓存控制:通过 HTTP 头部(如
Cache-Control
、Expires
等)控制缓存行为。- 使用
Cache-Control
控制缓存有效期。 - 使用
Expires
指定缓存的过期时间。
- 使用
在 Java 中,使用 Servlet 或 Spring 框架来设置缓存头部。
Servlet 示例:
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
public class CacheControlServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 设置缓存控制头部,设置最大缓存时间为 1 小时
response.setHeader("Cache-Control", "max-age=3600");
response.setHeader("Expires", "Wed, 21 Oct 2023 07:28:00 GMT");
// 设置响应内容
PrintWriter out = response.getWriter();
out.println("This response is cached for 1 hour.");
}
}
Spring 示例:
在 Spring 控制器中设置缓存头部:
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.http.ResponseEntity;
@RestController
public class CacheController {
@GetMapping("/cache")
public ResponseEntity<String> getCachedResponse() {
return ResponseEntity.ok()
.header("Cache-Control", "max-age=3600") // 设置最大缓存时间为 1 小时
.header("Expires", "Wed, 21 Oct 2023 07:28:00 GMT") // 设置过期时间
.body("This response is cached for 1 hour.");
}
}
2.2 代理缓存(Proxy Cache)
- 代理缓存是指代理服务器在处理客户端请求时缓存资源,以便其他客户端可以共享该资源,减少重复请求。
例如,设置代理缓存:
response.setHeader("Cache-Control", "public, max-age=3600"); // 允许代理服务器缓存
2.3 CDN 缓存(Content Delivery Network)
- CDN 缓存:CDN 节点缓存资源并分发到全球用户,减少请求延迟并加速资源加载。
在 Java 中,通常通过设置 Cache-Control
头部和 CDN 配置来使用缓存:
response.setHeader("Cache-Control", "public, max-age=86400"); // 资源缓存 24 小时
2.4 服务器端缓存
- 内存缓存:可以使用如 Redis 或 Memcached 等缓存工具来缓存数据。
- 文件缓存:将动态生成的页面或数据存储为文件,避免重复计算。
Redis 缓存(Java 示例):
使用 Jedis
(Redis 客户端)来缓存数据:
import redis.clients.jedis.Jedis;
public class RedisCacheExample {
public static void main(String[] args) {
Jedis jedis = new Jedis("localhost");
// 设置缓存
jedis.set("popular_items", "item1, item2, item3");
// 获取缓存
String cachedData = jedis.get("popular_items");
System.out.println("Cached Data: " + cachedData);
}
}
2.5 移动端缓存
- 移动端通常通过本地存储(如 SharedPreferences、SQLite)来缓存数据。
- 在 Java 后端与移动端的接口中,可以通过设置正确的 HTTP 头部来支持缓存。
例如,可以使用类似以下的方式向移动端应用发送缓存头:
response.setHeader("Cache-Control", "max-age=86400"); // 缓存 1 天
2.6 Web 应用缓存(Service Worker)
- Web 应用可以通过 Service Worker 来缓存资源,实现离线功能。
- Java 后端可以为前端提供静态资源,这些资源可以通过 Service Worker 进行缓存。
Service Worker(前端 JS 示例):
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open('my-cache').then((cache) => {
return cache.addAll([
'/index.html',
'/styles.css',
'/app.js',
]);
})
);
});
self.addEventListener('fetch', (event) => {
event.respondWith(
caches.match(event.request).then((cachedResponse) => {
return cachedResponse || fetch(event.request);
})
);
});
3. 常见 HTTP 头部字段
3.1 Cache-Control
- 控制浏览器缓存的行为,常用指令包括:
max-age=<seconds>
:资源最大缓存时间(秒)。public
:资源可以被任何缓存存储(浏览器、代理服务器)。private
:资源仅能被客户端缓存。no-cache
:需要重新验证资源有效性。no-store
:禁止缓存。
在 Java 后端中可以通过设置 Cache-Control
来控制缓存:
response.setHeader("Cache-Control", "max-age=86400"); // 缓存 1 天
3.2 Expires
- 指定资源的过期时间,过期后浏览器必须重新向服务器请求资源。
response.setHeader("Expires", "Wed, 21 Oct 2023 07:28:00 GMT");
3.3 Last-Modified
- 服务器返回资源的最后修改时间。客户端可以通过
If-Modified-Since
请求头向服务器确认资源是否更新。
Java 示例:
response.setHeader("Last-Modified", "Wed, 21 Oct 2023 07:28:00 GMT");
3.4 ETag
- 资源的唯一标识符,通常是资源内容的哈希值。客户端可以通过
If-None-Match
请求头验证缓存是否更新。
response.setHeader("ETag", "abc123");
4. 缓存策略
4.1 强缓存(Strong Cache)
- 在缓存有效期内,客户端直接使用缓存,不会向服务器发送请求。
- 由
Cache-Control
或Expires
控制。
- 由
response.setHeader("Cache-Control", "max-age=86400"); // 缓存 1 天
4.2 协商缓存(Conditional Cache)
- 客户端存储缓存,但每次请求前会向服务器确认资源是否更新。如果没有更新,服务器返回 304 状态码。
- 通过
ETag
或Last-Modified
验证。
- 通过
Java 示例:检查资源是否修改
String lastModified = "Wed, 21 Oct 2023 07:28:00 GMT";
response.setHeader("Last-Modified", lastModified);
String ifModifiedSince = request.getHeader("If-Modified-Since");
if (ifModifiedSince != null && ifModifiedSince.equals(lastModified)) {
response.setStatus(HttpServletResponse.SC_NOT_MODIFIED); // 返回 304 状态码
return;
}
5. 缓存管理和挑战
5.1 缓存失效
- 缓存内容可能过时,必须确保在资源更新时及时清除或更新缓存,避免展示过时的数据。
5.2 缓存一致性
- 在分布式缓存系统中,确保缓存节点之间的一致性是个挑战。必须保持缓存数据与源数据同步。
5.3 安全性问题
- 对于敏感信息(如账户、支付数据等),需要确保数据不被缓存,避免泄露。
6. 缓存优化策略
6.1 设置合理的缓存时间
- 根据资源的更新频率设置
max-age
和Expires
,静态资源缓存时间长,动态资源缓存时间短。
response.setHeader("Cache-Control", "max-age=3600"); // 缓存 1 小时
6.2 使用版本化文件
- 通过版本号或哈希值(如
app.js?v=2
)确保资源更新时强制浏览器重新加载最新版本。