前言
http的缓存机制可用于提升和优化网络请求的效率。这个对于项目优化来说也会有一定的帮助,所以本文就来总结一下http缓存机制。同时也会结合okhttp源码,了解okhttp是如何实现这一缓存机制的。
本文基于okhttp 3.14.9
github地址:github.com/square/okht…
gradle依赖:implementation group: ‘com.squareup.okhttp3’, name: ‘okhttp’, version: ‘3.14.9’
本文参考:详解Http缓存策略
Okhttp.Cache
先来说说如何cache管理的设置以及使用。
val okHttpClient = OkHttpClient.Builder()
.cache(Cache(this.cacheDir, 20 * 1024 * 1024))
.build()
// OkhttpClient.Builder.java
public Builder cache(@Nullable Cache cache) {
this.cache = cache;
this.internalCache = null;
return this;
}
复制代码
创建OkHttpClient的时候,可以设置一个okhttp3.Cache
的类型,传入的参数为缓存保存的文件路径,以及最大容量。
// Cache.java
final InternalCache internalCache = new InternalCache() {
@Override public @Nullable Response get(Request request) throws IOException {
return Cache.this.get(request);
}
@Override public @Nullable CacheRequest put(Response response) throws IOException {
return Cache.this.put(response);
}
@Override public void remove(Request request) throws IOException {
Cache.this.remove(request);
}
@Override public void update(Response cached, Response network) {
Cache.this.update(cached, network);
}
@Override public void trackConditionalCacheHit() {
Cache.this.trackConditionalCacheHit();
}
@Override public void trackResponse(CacheStrategy cacheStrategy) {
Cache.this.trackResponse(cacheStrategy);
}
};
复制代码
Cache
中的internalCache
属性是提供给外部调用获取或者保存缓存的接口。
// OkhttpClient.java
@Nullable InternalCache internalCache() {
return cache != null ? cache.internalCache : internalCache;
}
复制代码
OkhttpClient
提供一个方法获取该internalCache
属性。
// RealCall.java
Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
List<Interceptor> interceptors = new ArrayList<>();
interceptors.addAll(client.interceptors());
interceptors.add(new RetryAndFollowUpInterceptor(client));
interceptors.add(new BridgeInterceptor(client.cookieJar()));
interceptors.add(new CacheInterceptor(client.internalCache()));
interceptors.add(new ConnectInterceptor(client));
复制代码
网络请求发起时,getResponseWithInterceptorChain()
方法会构建Okhttp的责任链,这时创建CacheInterceptor
的时候就会传入上述的internalCache
对象,用于后续的缓存策略使用。
故Okhttp的缓存机制处理,会发生在CacheInterceptor.intercept
方法中。
// CacheInterceptor.java
final @Nullable InternalCache cache;
public CacheInterceptor(@Nullable InternalCache cache) {
this.cache = cache;
}
@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;
复制代码
从上述代码段可知,在请求时责任链走到CacheInterceptor
时,会先从cache中获取对应已缓存的response。ps:这里的cache.get正是上述的internalCache对象的get方法。
通过创建CacheStrategy
对象调用其get方法,获取到一个可用的cacheResponse
。
public CacheStrategy get() {
CacheStrategy candidate = getCandidate();
if (candidate.networkRequest != null && request.cacheControl().onlyIfCached()) {
// We're forbidden from using the network and the cache is insufficient.
return new CacheStrategy(null, null);
}
return candidate;
}
复制代码
CacheStrategy.get
方法中,会调用getCandidate()
方法,所以getCandidate()
方法即为缓存策略的体现。
本文后续将会结合CacheInterceptor.intercept
以及getCandidate()
方法介绍缓存机制。
强缓存
http缓存机制大致可分为强缓存
与对比缓存
,先来看强缓存
。