搞点基础的——关于http缓存机制的那些事

前言

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缓存机制大致可分为强缓存对比缓存,先来看强缓存

客户端缓存请求是否存在符合规定的缓存?存在未过期的缓存,直接返回。客户端缓存

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享