`

HttpClient 4.3教程 第六章 HTTP缓存

 
阅读更多

 

6.1.基本概念

HttpClient的缓存机制提供一个与HTTP/1.1标准兼容的缓存层 – 相当于Java的浏览器缓存。HttpClient缓存机制的实现遵循责任链(Chain of Responsibility)设计原则,默认的HttpClient是没有缓存的,有缓存机制的HttpClient可以用来临时替代默认的HttpClient,如果开启了缓存,我们的请求结果就会从缓存中获取,而不是从目标服务器中获取。如果在Get请求头中设置了If-Modified-Since或者If-None-Match参数,那么HttpClient会自动向服务器校验缓存是否过期。

HTTP/1.1版本的缓存是语义透明的,意思是无论怎样,缓存都不应该修改客户端与服务器之间传输的请求/响应数据包。因此,在existing compliant client-server relationship中使用带有缓存的HttpClient也应该是安全的。虽然缓存是客户端的一部分,但是从Http协议的角度来看,缓存机制是为了兼容透明的缓存代理。

最后,HttpClient缓存也支持RFC 5861规定的Cache-Control拓展(stale-if-error'和stale-while-revalidate`)。

当开启缓存的HttpClient执行一个Http请求时,会经过下面的步骤:

  • 检查http请求是否符合HTTP 1.1的基本要求,如果不符合就尝试修正错误。
  • 刷新该请求无效的缓存项。(Flush any cache entries which would be invalidated by this request.)
  • 检测该请求是否可以从缓存中获取。如果不能,直接将请求发送给目标服务器,获取响应并加入缓存。
  • 如果该请求可以从缓存中获取,HttpClient就尝试读取缓存中的数据。如果读取失败,就会发送请求到目标服务器,如果可能的话,就把响应缓存起来。
  • 如果HttpClient缓存的响应可以直接返回给请求,HttpClient就会构建一个包含ByteArrayEntityBasicHttpResponse对象,并将它返回给http请求。否则,HttpClient会向服务器重新校验缓存。
  • 如果HttpClient缓存的响应,向服务器校验失败,就会向服务器重新请求数据,并将其缓存起来(如果合适的话)。
    当开启缓存的HttpClient收到服务器的响应时,会经过下面的步骤:
  • 检查收到的响应是否符合协议兼容性
  • 确定收到的响应是否可以缓存
  • 如果响应是可以缓存的,HttpClient就会尽量从响应消息中读取数据(大小可以在配置文件进行配置),并且缓存起来。
  • 如果响应数据太大,缓存或者重构消耗的响应空间不够,就会直接返回响应,不进行缓存。
    需要注意的是,带有缓存的HttpClient不是HttpClient的另一种实现,而是通过向http请求执行管道中插入附加处理组件来实现的。

6.2. RFC-2616 Compliance

HttpClient的缓存机制和RFC-2626文档规定是无条件兼容的。也就是说,只要指定了MUSTMUST NOTSHOULD或者SHOULD NOT这些Http缓存规范,HttpClient的缓存层就会按照指定的方式进行缓存。即当我们使用HttpClient的缓存机制时,HttpClient的缓存模块不会产生异常动作。

6.3. 使用范例

下面的例子讲述了如何创建一个基本的开启缓存的HttpClient。并且配置了最大缓存1000个Object对象,每个对象最大占用8192字节数据。代码中出现的数据,只是为了做演示,而过不是推荐使用的配置。

    CacheConfig cacheConfig = CacheConfig.custom()
            .setMaxCacheEntries(1000)
            .setMaxObjectSize(8192)
            .build();
    RequestConfig requestConfig = RequestConfig.custom()
            .setConnectTimeout(30000)
            .setSocketTimeout(30000)
            .build();
    CloseableHttpClient cachingClient = caching HttpClients.custom()
            .setCacheConfig(cacheConfig)
            .setDefaultRequestConfig(requestConfig)
            .build();

    HttpCacheContext context = HttpCacheContext.create();
    HttpGet httpget = new HttpGet("http://www.mydomain.com/content/");
    CloseableHttpResponse response = cachingClient.execute(httpget, context);
    try {
        CacheResponseStatus responseStatus = context.getCacheResponseStatus();
        switch (responseStatus) {
            case CACHE_HIT:
                System.out.println("A response was generated from the cache with " +
                        "no requests sent upstream");
                break;
            case CACHE_MODULE_RESPONSE:
                System.out.println("The response was generated directly by the " +
                "caching module");
                break;
            case CACHE_MISS:
                System.out.println("The response came from an upstream server");
                break;
            case VALIDATED:
                System.out.println("The response was generated from the cache " +
                "after validating the entry with the origin server");
                break;
        }
    } finally {
        response.close();
     }

6.4. 配置

有缓存的HttpClient继承了非缓存HttpClient的所有配置项和参数(包括超时时间,连接池大小等配置项)。如果需要对缓存进行具体配置,可以初始化一个CacheConfig对象来自定义下面的参数:

  • Cache size(缓存大小). 如果后台存储支持,我们可以指定缓存的最大条数,和每个缓存中存储的response的最大size。
  • Public/private cacheing(公用/私有 缓存). 默认情况下,缓存模块会把缓存当做公用的缓存,所以缓存机制不会缓存带有授权头消息或者指定Cache-Control:private的响应。但是如果缓存只会被一个逻辑上的用户使用(和浏览器饿缓存类似),我们可能希望关闭缓存共享机制。
  • Heuristic caching(启发式缓存)。即使服务器没有明确设置缓存控制headers信息,每个RFC2616缓存也会存储一定数目的缓存。这个特征在HttpClient中默认是关闭的,如果服务器不设置控制缓存的header信息,但是我们仍然希望对响应进行缓存,就需要在HttpClient中打开这个功能。激活启发式缓存,然后使用默认的刷新时间或者自定义刷新时间。更多启发式缓存的信息,可以参考Http/1.1 RFC文档的13.2.2小节,13.2.4小节。
  • Background validation(后台校验)。HttpClient的缓存机制支持RFC5861的stale-while-revalidate指令,它允许一定数目的缓存在后台校验是否过期。我们可能需要调整可以在后台工作的最大和最小的线程数,以及设置线程在回收前最大的空闲时间。当没有足够线程来校验缓存是否过期时,我们可以指定排队队列的大小。

6.4.存储介质

默认,HttpClient缓存机制将缓存条目和缓存的response放在本地程序的jvm内存中。这样虽然提供高性能,但是当我们的程序内存有大小限制的时候,这就会变得不太合理。因为缓存的生命中期很短,如果程序重启,缓存就会失效。当前版本的HttpClient使用EhCache和memchached来存储缓存,这样就支持将缓存放到本地磁盘或者其他存储介质上。如果内存、本地磁盘、外地磁盘,都不适合你的应用程序,HttpClient也支持自定义存储介质,只需要实现HttpCacheStorage接口,然后在创建HttpClient时,使用这个接口的配置。这种情况,缓存会存储在自定义的介质中,但是you will get to reuse all of the logic surrounding HTTP/1.1 compliance and cache handling. 一般来说,可以创建出支持任何键值对指定存储(类似Java Map接口)的HttpCacheStorage,用于进行原子更新。

最后,通过一些额外的工作,还可以建立起多层次的缓存结构;磁盘中的缓存,远程memcached中的缓存,虚拟内存中的缓存,L1/L2处理器中的缓存等。

 

分享到:
评论

相关推荐

    开涛高可用高并发-亿级流量核心技术

    10.3 HttpClient客户端缓存 192 10.3.1 主流程 195 10.3.2 清除无效缓存 195 10.3.3 查找缓存 196 10.3.4 缓存未命中 198 10.3.5 缓存命中 198 10.3.6 缓存内容陈旧需重新验证 202 10.3.7 缓存内容无效需重新执行...

    OPhone应用开发权威指南(黄晓庆)

    第6章 数据持久化存储 223 6.1 文件存储 223 6.1.1 存储至默认文件夹 224 6.1.2 存储至指定文件夹 226 6.1.3 存储至SD卡 227 6.1.4 读取资源文件 228 6.2 SharePreference 229 6.3 SQLite 233 6.3.1 创建数据库 234 ...

    大型分布式网站架构与实践

    第1章 面向服务的体系架构(SOA) 1  本章主要介绍和解决以下问题,这些也是全书的基础:  HTTP协议的工作方式与HTTP网络协议栈的结构。  如何实现基于HTTP协议和TCP协议的RPC调用,它们之间有何差别,分别适应...

    低清版 大型门户网站是这样炼成的.pdf

    第6章 充分利用spring 2.5的ioc利器统管bean世界 349 6.1 java程序员的春天厚礼—spring 2.5 349 6.1.1 爱上spring 2.5的十大理由 350 6.1.2 一睹spring 2.5芳容 351 6.1.3 spring 2.5拿手戏——控制反转与依赖...

Global site tag (gtag.js) - Google Analytics