6.OkHttp的缓存管理
2017-07-03 13:05
295 查看
6.OkHttp的缓存管理
番外篇有讲到, Http头里面有个Cache-Control的字段,这个字段就是来处理缓存的,我们先来了解一下Cache-Control
Cache-Control的运用
Cache-Control : cache-directiveCache-directive | 说明 |
---|---|
public | 所有内容都将被缓存(客户端和代理服务器都可缓存) |
private | 内容只缓存到私有缓存中(仅客户端可以缓存,代理服务器不可缓存) |
no-cache | 必须先与服务器确认返回的响应是否被更改,然后才能使用该响应来满足后续对同一个网址的请求。因此,如果存在合适的验证令牌 (ETag),no-cache 会发起往返通信来验证缓存的响应,如果资源未被更改,可以避免下载。 |
no-store | 所有内容都不会被缓存到缓存或 Internet 临时文件中 |
must-revalidation/proxy-revalidation | 如果缓存的内容失效,请求必须发送到服务器/代理以进行重新验证 |
max-age=xxx (xxx is numeric) | 缓存的内容将在 xxx 秒后失效, 这个选项只在HTTP 1.1可用, 并如果和Last-Modified一起使用时, 优先级较高 |
Last-Modified 实体头部字段值通常用作一个缓存验证器。简单来说,如果实体值在 Last-Modified 值之后没有被更改,则认为该缓存条目有效。ETag 响应头部字段值是一个实体标记,它提供一个 “不透明” 的缓存验证器。这可能在以下几种情况下提供更可靠的验证:不方便存储修改日期;HTTP 日期值的 one-second 解决方案不够用;或者原始服务器希望避免由于使用修改日期而导致的某些冲突。
由于开启缓存讲道理应该是服务端配置的,但是我们现在是研究用,所以自己在本地写个NetworkInterceptor加进去
代码如下:
“““java
public class CacheInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Response response = chain.proceed(request);
Response response1 = response.newBuilder()
.removeHeader(“Pragma”)
.removeHeader(“Cache-Control”)
.header(“Cache-Control”,”max-age=”+ 3600*24*30)
.build();
return response1; }
}
“““
在这边我们手动的在返回的header加入Cache-Control,下面 我们来分析他的流程
OkHttp缓存管理
如果要支持缓存的话 要在初始化OkHttpClient的时候进行相应的设置,例如“““java
public class TestMain {
private static final long cacheSize = 1024 * 1024 * 20;//缓存文件最大限制大小20M private static String cachedirectory = "/Users/liuxiaohu/Desktop" + "/caches"; //设置缓存文件路径 private static Cache cache = new Cache(new File(cachedirectory), cacheSize); // public static void main(String[] args) { OkHttpClient okHttpClient = new OkHttpClient.Builder() .cache(cache) .addNetworkInterceptor(new CacheInterceptor()) .build(); (..... 省略一大堆代码) }
}
“““
这边的话我们初始化cache的大小,目录等,然后设置进去,注意
.addNetworkInterceptor(new CacheInterceptor())这边是测试的 讲道理需要后台配置
还在等什么呢?请求搞起,目地已经非常明确了 就是
CacheInterceptor按照以往的姿势,看他的初始化和
intercept方法
“““java
//初始化在 RealCall 初始化拦截链那边
//ReaCll.java
interceptors.add(new CacheInterceptor(client.internalCache()));
//internalCache 在 OkHttpClient.java 里 ,如果你构建的时候用的是cahe构建的,那这边返回的就是cache
InternalCache internalCache() {
return cache != null ? cache.internalCache : internalCache;
}
//这边的cache就是你实例化的Cache Cache.java 这个类主要就是负责操作缓存,这边知道cache后我们来看CacheInterceptor#intercept(Chain chain)
@Override public Response intercept(Chain chain) throws IOException {
Response cacheCandidate = cache != null
? cache.get(chain.request())
: null;
//记录当前时间戳 long now = System.currentTimeMillis(); CacheStrategy strategy = new CacheStrategy.Factory(now, chain.request(), cacheCandidate).get(); Request networkRequest = strategy.networkRequest; Response cacheResponse = strategy.cacheResponse; //如果缓存不为空,添加响应计数 if (cache != null) { cache.trackResponse(strategy); } if (cacheCandidate != null && cacheResponse == null) { closeQuietly(cacheCandidate.body()); // The cache candidate wasn't applicable. Close it. 缓存候选者不适用。关闭它 } // If we're forbidden from using the network and the cache is insufficient, fail.如果我们被禁止使用网络并且缓存不够,则失败。 if (networkRequest == null && cacheResponse == null) { return new Response.Builder() .request(chain.request()) .protocol(Protocol.HTTP_1_1) .code(504) .message("Unsatisfiable Request (only-if-cached)") .body(Util.EMPTY_RESPONSE) .sentRequestAtMillis(-1L) .receivedResponseAtMillis(System.currentTimeMillis()) .build(); } // If we don't need the network, we're done.如果我们不需要网络,我们就完成了 if (networkRequest == null) { return cacheResponse.newBuilder() .cacheResponse(stripBody(cacheResponse)) .build(); } Response networkResponse = null; try { networkResponse = chain.proceed(networkRequest); } finally { // If we're crashing on I/O or otherwise, don't leak the cache body.如果I / O或其他正在崩溃不要泄漏缓存主体。 if (networkResponse == null && cacheCandidate != null) { closeQuietly(cacheCandidate.body()); } } // If we have a cache response too, then we're doing a conditional get.如果我们也有缓存响应,那么我们正在做一个条件去获取。 if (cacheResponse != null) { if (networkResponse.code() == HTTP_NOT_MODIFIED) { Response response = cacheResponse.newBuilder() .headers(combine(cacheResponse.headers(), networkResponse.headers())) .sentRequestAtMillis(networkResponse.sentRequestAtMillis()) .receivedResponseAtMillis(networkResponse.receivedResponseAtMillis()) .cacheResponse(stripBody(cacheResponse)) .networkResponse(stripBody(networkResponse)) .build(); networkResponse.body().close(); // Update the cache after combining headers but before stripping the // Content-Encoding header (as performed by initContentStream()). //在组合头后,但在剥离Content-Encoding头(由initContentStream()执行)之前更新缓存。 cache.trackConditionalCacheHit(); cache.update(cacheResponse, response); return response; } else { closeQuietly(cacheResponse.body()); } } Response response = networkResponse.newBuilder() .cacheResponse(stripBody(cacheResponse)) .networkResponse(stripBody(networkResponse)) .build(); if (cache != null) { if (HttpHeaders.hasBody(response) && CacheStrategy.isCacheable(response, networkRequest)) { // Offer this request to the cache.将此请求提供给缓存 CacheRequest cacheRequest = cache.put(response); return cacheWritingResponse(cacheRequest, response); } if (HttpMethod.invalidatesCache(networkRequest.method())) { try { cache.remove(networkRequest); } catch (IOException ignored) { // The cache cannot be written.缓存无法写入。 } } } return response;
}
“““
总的来说流程还是比较简单的,我们来整理一下,
初始化OkHttpClient的时候初始化Cache,传入地址和最大缓存大小,Cache的构造函数里初始化了DiskLruCache
intercept中调用了Cache的get方法,传入的是当前的request,获取到缓存
从缓存中获取请求和返回,如果当前缓存不为空,则添加Cache的计数
如果缓存不适用,关闭当前的缓存
如果我们被禁止使用网络并且缓存不够,则失败,返回code为504。
如果网络请求为null,那么久完成这次请求 ,返回从缓存中读取的返回体
如果上面都没有,那么走真正的网络请求。
然后判断是否有缓存,如果有,写入缓存,返回
相关文章推荐
- Squid+MRTG实现完善的缓存代理和http服务加速代理
- ASP.NET状态管理之四(暂存状态HttpContext.Items)
- 发布全部开源的Asp.net 2.0 RBAC 权限管理系统了,大家支持下。测试版发布: http://Wenzy.37live.com
- AggregateCacheDependency、CacheDependency、SqlCacheDependency Asp.net 2.0和Sql Server的缓存管理和使用ObjectBuilder改造PetShop4 的缓存示例
- 数据库的缓存管理[ASPNET2.0深入挖掘系列听后感]
- Hibernate学习笔记(六)--管理Hibernate的缓存
- [转]ASP.NET 缓存(七)--根据 HTTP 标头缓存页的版本
- ASP.NET与客户端缓存之HTTP协议的理解
- ASP.NET状态管理之六(缓存Cache)
- 面前我发现的最好的在线日程管理工具 http://www.kiko.com/
- 动态的管理ASP.NET DataGrid数据列(转自:http://dev.21tx.com)
- DotProject开源项目管理(http://blog.csdn.net/yuandj)
- AggregateCacheDependency、CacheDependency、SqlCacheDependency Asp.net 2.0和Sql Server的缓存管理和使用ObjectBuilder改造PetShop4 的缓存示例
- 都是缓存惹得祸 (转至http://blog.csdn.net/kwklover/)
- 解析Winndows 2000/XP物理内存管理(http://webcrazy.yeah.net)
- [译]管理Windows 2000 Pro中的DNS客户端缓存
- 事务管理最佳实践全面解析(转)http://blog.csdn.net/shendl/archive/2006/11/27/1415958.aspx
- Squid+MRTG实现完善的缓存代理和http服务加速代理