Apache HttpClient 4.5.x 学习总结十三:HTTP Caching(HTTP缓存)
第6章 HTTP缓存
6.1 基本概念
HttpClient缓存模块为HttpClient提供了符合HTTP/1.1标准的缓存层(相当于浏览器的缓存)。其实现采用责任链设计模式,缓存版HttpClient可直接替代默认的非缓存版本:能从缓存直接响应的请求不会访问源服务器。当缓存条目过期时,系统会自动通过条件GET请求(使用If-Modified-Since和If-None-Match请求头)向源服务器验证有效性。
HTTP/1.1缓存设计遵循语义透明原则:缓存不应改变客户端与服务器间请求-响应的语义。因此将缓存版HttpClient接入现有客户端-服务器体系是安全的。虽然缓存模块属于客户端,但其实现兼容透明缓存代理的要求。
此外,该模块支持RFC 5861定义的Cache-Control扩展指令(stale-if-error和stale-while-revalidate)。
缓存请求执行流程:
- 检查请求是否符合HTTP 1.1协议并修正
- 清除该请求可能失效的缓存条目
- 若请求无法通过缓存响应,则直接访问源服务器(响应可能被缓存)
- 若请求可通过缓存响应:
- 缓存存在:返回缓存响应(需验证时向源服务器重新验证)
- 缓存不存在:访问源服务器并缓存响应
缓存响应接收流程:
- 检查响应是否符合协议规范
- 判断响应是否可缓存
- 若可缓存且未超过配置大小,则存入缓存
- 若响应过大则直接返回,不缓存
关键说明:缓存版HttpClient并非独立实现,而是作为请求执行管道的附加处理组件。
6.2 RFC-2616合规性
HttpClient缓存层完全符合RFC-2616规范,严格遵循协议中关于MUST/MUST NOT/SHOULD/SHOULD NOT的要求,确保行为正确性。
6.3 使用示例
以下配置创建基础缓存HttpClient:
- 最多缓存1000个对象
- 单个响应体最大8192字节
注:示例数值仅作演示,非生产建议
// 缓存配置
CacheConfig cacheConfig = CacheConfig.custom()
.setMaxCacheEntries(1000) // 最大缓存条目
.setMaxObjectSize(8192) // 单个对象最大字节数
.build();
// 请求配置
RequestConfig requestConfig = RequestConfig.custom()
.setConnectTimeout(30000) // 连接超时30秒
.setSocketTimeout(30000) // 数据传输超时30秒
.build();
// 创建缓存客户端
CloseableHttpClient cachingClient = CachingHttpClients.custom()
.setCacheConfig(cacheConfig)
.setDefaultRequestConfig(requestConfig)
.build();
// 执行请求并检查缓存状态
HttpCacheContext context = HttpCacheContext.create();
HttpGet httpget = new HttpGet("http://www.mydomain.com/content/");
try (CloseableHttpResponse response = cachingClient.execute(httpget, context)) {
switch (context.getCacheResponseStatus()) {
case CACHE_HIT: // 缓存直接命中(未访问源服务器)
case CACHE_MODULE_RESPONSE: // 缓存模块直接生成响应
case CACHE_MISS: // 来自源服务器的新响应
case VALIDATED: // 缓存经源服务器验证后使用
}
}
6.4 配置选项
缓存HttpClient继承所有非缓存版的配置(如超时、连接池),并通过CacheConfig定制缓存行为:
| 配置项 | 作用 |
|---|---|
| 缓存大小 | 限制最大缓存条目数和响应体大小(需后端存储支持) |
| 公共/私有缓存 | 默认公共缓存(不缓存带Authorization头或Cache-Control: private的响应),单用户使用时需关闭 |
| 启发式缓存 | 当源服务器未设置缓存头时,按规则自动缓存(默认关闭) |
| 后台验证 | 支持RFC5861的stale-while-revalidate指令,可配置后台验证线程参数 |
6.5 存储后端
- 默认内存存储:高性能但受JVM内存限制,重启后缓存丢失
- 扩展方案:
EhCache:支持磁盘持久化memcached:外部进程存储
- 自定义存储:实现
HttpCacheStorage接口,复用HTTP合规逻辑 - 多级缓存:可构建分层缓存(如内存+磁盘),类似CPU的L1/L2缓存设计
核心知识点总结:
-
缓存本质
- 责任链模式实现的语义透明缓存层
- 核心目标:减少源服务器请求,提升性能
-
工作流程
- 请求阶段:优先检查缓存 → 无效则访问源服务器
- 响应阶段:协议检查 → 缓存策略判断 → 存储控制
-
高级特性
- 条件验证(
If-Modified-Since等) - RFC 5861指令支持(
stale-if-error) - 启发式缓存(无缓存头时的智能处理)
- 条件验证(
-
配置要点
- 容量限制(条目数/响应体大小)
- 公共缓存 vs 私有缓存场景
- 后台验证线程池调优
-
存储架构
- 内存:默认方案,适合临时缓存
- 磁盘/外部存储:持久化方案(EhCache/memcached)
- 自定义接口:灵活适配键值存储系统
通俗易懂的解释:
HTTP缓存 ≈ 快递驿站
- 基础逻辑
- 你下单(发送请求)时,驿站先检查是否有现成包裹(缓存命中)
- 若无则向商家订货(访问源服务器),新包裹可能存驿站(缓存响应)
- 取包裹时驿站检查是否过期(缓存验证),过期则联系商家确认(条件GET)
- 高级能力
- 语义透明:驿站不会拆你的包裹(不改变数据内容)
- 智能囤货:即使商家没说能囤(无缓存头),驿站按规则存常用品(启发式缓存)
- 专属货架:私有缓存像VIP货架(如带密码的包裹单独存放)
- 存储方案
- 小货架:内存存储 → 取货快但容量小(重启清空)
- 大仓库:磁盘/memcached → 能存大件(文件),重启不丢
- 自定义仓库:用自家仓库(实现接口),但遵守相同管理规则
- 性能秘籍
- 后台验货:边让你取旧包裹(
stale-while-revalidate),边后台检查新鲜度- 多级缓存:像驿站门口放畅销品(内存),后院存大件(磁盘)
典型场景:
- 频繁访问的API数据 → 内存缓存提速
- 大型静态文件(图片/视频)→ EhCache磁盘存储
- 分布式系统 → memcached统一缓存池
浙公网安备 33010602011771号