OkHttp3源码-CacheInterceptor
interceptor的详细过程
看过伪代码, 现在来看详细过程, 就好多了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
| @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()); }
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 (networkRequest == null) { return cacheResponse.newBuilder() .cacheResponse(stripBody(cacheResponse)) .build(); }
Response networkResponse = null; try { networkResponse = chain.proceed(networkRequest); } finally { if (networkResponse == null && cacheCandidate != null) { closeQuietly(cacheCandidate.body()); } }
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();
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)) { CacheRequest cacheRequest = cache.put(response); return cacheWritingResponse(cacheRequest, response); } if (HttpMethod.invalidatesCache(networkRequest.method())) { try { cache.remove(networkRequest); } catch (IOException ignored) { } } }
return response; }
|
Cache
OkHttpClient创建时添加cache:
1 2 3 4 5
| OkHttpClient.Builder builder = new OkHttpClient.Builder() .connectTimeout(15, TimeUnit.SECONDS) .writeTimeout(20, TimeUnit.SECONDS) .readTimeout(20, TimeUnit.SECONDS) .cache(new Cache(context.getExternalCacheDir(), 10*1024*1024));
|
InternalCache和Cache:
InternalCache时在框架内部进行调用的接口, Cache类中有InternalCache的成员变量
实现原理:
封装了对DiskLruCach的操作
注意点:
Cache类只能缓存get请求. 在put方法的注释中提到, 从技术上来说, 是可以缓存post方法的response的, 但是这样的代价太高, 效率很低.
首先,okhttp缓存的key是url。 而post请求包含了body。
而且对于标准的RESTful请求,GET就是用来获取数据,最适合使用缓存,而对于数据的其他操作缓存意义不大或者根本不需要缓存。
CacheStrategy
构造方法
1
| CacheStrategy(Request networkRequest, Response cacheResponse)
|
生成的CacheStrategy中有2个变量,networkRequest和cacheResponse,如果networkRequest为null,则表示不进行网络请求;而如果cacheResponse为null,则表示没有有效的缓存。
CacheStrategy.Factory
1
| public Factory(long nowMillis, Request request, Response cacheResponse)
|
这是CacheStrategy的一个静态内部类, 代码就不贴了. 主要作用是根据参数和创建CacheStrategy
request参数中附带有用户对缓存策略的配置: ( .cacheControl)
类如:
1 2 3 4
| Request request = new Request.Builder() .cacheControl(new CacheControl.Builder().noCache().build()) .url("http://publicobject.com/helloworld.txt") .build();
|