天天看点

《HttpClient官方文档》第六章 HTTP 缓存

httpclient cache 提供了用httpclient(等效浏览器缓存的java实现)来兼容http / 1.1的缓存层。实现遵循责任链模式,httpclient缓存的实现类可以替代默认无缓存的httpclient;完全可以通过缓存实现的请求将不会触发实际的原始请求。在可以的情况下,使用gets条件if-modified-since和/or if-none-match请求头,会自动验证旧的缓存项。http / 1.1缓存一般被设计成语义透明的,也就是说,缓存不会改变客户端和服务器端的请求响应之间交换的意义。因此,向一个现有的客户端-服务器的关系中添加httpclient是安全的。尽管从一个http协议的角度来看,缓存模块是客户端的一部分,实现的目标是满足基于透明缓存代理的要求。最后,缓存httpclient包括支持rfc 5861(stale-if-error和stale-while-revalidate)指定的cache – control扩展。 当缓存httpclient执行一个请求时,它会通过以下流程:

检查要求是否符合基本的http 1.1协议并尝试正确的请求。

刷新当前请求导致无效的一些缓存项。

确定当前请求可以从缓存中提供。如果不能, 则直接将这个请求发送给原始服务器并换回响应,如果合适的话保存缓存.

如果是cache-servable请求时,将尝试从缓存中读取。当缓存中没有的情况下,调用原始的服务器,如果可以的话将响应缓存。

如果缓存中的响应能够被当做一个响应提供服务,构造一个包含bytearrayentity的basichttpresponse并返回。否则,尝试重新验证对原始服务器的缓存项.

当一个缓存的响应不能重新生效的情况下,调用原始服务器,如果可以的话缓存响应.

当缓存httpclient收到响应时,它通过以下流程:

根据协议内容,检查响应。

确定响应是否可以被缓存。

如果可以被缓存,读取配置中允许的最多内容,并将其保存在缓存中。

如果对缓存来说响应过大,则重新构建被消费的部分响应,并跳过缓存流程直接返回。

需要着重注意的是,httpclient cache本身并不是一个httpclient的不同实现,而是通过插件的方式作为一个额外管道执行请求。

我们相信httpclient缓存是无条件地符合rfc-2616。也就是说无论规范表明对于http缓存 必须、不必须、可以、不可以,缓存层都会试图以满足这些条件的方式实现。 这就意味着,当你使用缓存模块时,不会发生错误的行为。

下面是一个如何建立一个基本的缓存httpclient例子。根据配置,他会存储一个最大数量为1000的缓存实例,每个最多能够保存8192 bytes。这里的数字仅仅是个例子,并不是规定,也不能被看做成建议。

httpclient cache 继承了所有非缓存实现的配置项和参数(包括像超时时间、连接池大小这样的设置选项)。对于缓存的具体配置,可以根据以下几个方提供一个缓存配置实例指定行为:

缓存大小,后端存储支持这些限制,可以像最大的可缓存响应体大小一样指定缓存项的数量.

公共/私有缓存. 在默认情况下,缓存模块本身是一个共享缓存,例如,不会缓存带有授权请求头的响应和标记为”cache-control: private”的响应。然而,如果缓存仅仅被应用于一个“用户”(类似于浏览器缓存的行为)逻辑,那么它将关闭共享缓存设置。

启发式缓存. 按照rfc2616, 缓存可以缓存特定的缓存条目,即使没有显示原始设置的缓存控制头。这种行为在默认情况下是关闭的,但是如果你处理的是一个没有完全设置原始请求头的请求,你可能想要打开它。你需要一个可以启发式的缓存,然后指定一个默认的新生命周期,并且/或者资源被最后修改后的一小段时间。参考http/1.1 rfc的13.2.2和13.2.4部分,可以获得启发式缓存的更多细节。

后台验证. 缓存模块支持rfc5861的stale-while-revalidate指令,允许后台特定的缓存项重新生效。可以需要调整设置后台工作线程的最小和最大工作数量,以及他们回收前闲置的最大时间。没有足够的worker来跟上需求时,您还可以控制队列的大小用于重新生效线程。

默认的httpclient cache的实现会存储缓存项,并且在应用的jvm内存中缓存响应体。虽然这些能够提供高性能,但是有内存大小的限制,或者因为缓存项在应用重启后会失效,所以可能并不适用于您的应用。当前版本允许将缓存项保存到硬盘上,或者使用其他外部进程ehcache和memcached存储缓存项。如果这些选项满足不了你的应用,可以通过实现httpcachedstorage提供你自己的后台存储,并且在构建的时候提供给缓存httpclient。在这种情况下,缓存项会通过你自己的框架存储,但是会重用所有http/1.1协议的逻辑和缓存处理。一般来说,应该能够创建一个支持原子操作的key/value存储(类似于java的map接口)的httpcachedstorage实现。最后,通过一些额外的努力完全有可能建立一个多层缓存层次结构; 比如,包装一个内存中的缓存httpclient在磁盘上的存储缓存条目,在memcached中远程存储,后一种模式类似于虚拟内存,l1 / l2处理器缓存等。