Okhttp之五种拦截器

原理:主要是通过 5 个拦截器和 3 个队列(同步队列,异步队列,等待队列)工作,内部实现通过一个责任链模式完成,将网络请求的各个阶段封装到各个链条中,实现了各层的解耦

5个拦截器都是哪些?有什么作用

  • RetryAndFollowUpInterceptor(重试和重定向拦截器)
    第一个接触到请求,最后接触到响应;负责判断是否需要重新发起整个请求 。重试与重定向拦截器主要处理Response
  • BridgeInterceptor(桥接拦截器)
    补全请求,并对响应进行额外处理,完成应用层和网络层的桥接
  • CacheInterceptor(缓存拦截器)
    请求前查询缓存,获得响应并判断是否需要缓存
  • ConnectInterceptor(链接拦截器)
    与服务器完成TCP连接 (Socket),内部维护一个连接池,负责连接复用、创建连接、释放连接
  • CallServerInterceptor(请求服务拦截器)
    与服务器通信;封装请求数据与解析响应数据(如:HTTP报文)。里面用的okio库,主要是segment的机制运用内存共享和复用,数据不需要进行二次copy,尽可能少的去申请内存,同时也就降低了GC的频率。强了流与流交互,优化缓存策略减小内存压力和性能消耗

RetryAndFollowUpInterceptor (重试和重定向拦截器)

状态码 描述
1xx 信息,服务器收到请求,需要请求者继续执行操作
2xx 成功,操作被成功接收并处理
3xx 重定向,需要进一步的操作以完成请求
4xx 客户端错误,请求包含语法错误或无法完成请求
5xx 服务器错误,服务器在处理请求的过程中发生了错误

HTTP Code 常用状态码

RetryAndFollowUpInterceptor 总结

  • 是整个责任链中的第一个,是首次接触到Request与最后接收到 Response的,主要功能就是判断是否需要重试与重定向。
  • 重试的前提是出现了 RouteException 或IOException 。一旦在后续的拦截器执行过程中出现这两个异常,就会通过 recover 方法进行判断是否进行连接重试。
  • 重定向发生在重试的判定之后,如不满足重试的条件,还需要进一步调用 followUpRequest 根据Response 的响应码(如果直接请求失败, Response都不存在就会抛出异常)。 followup 最大发生20次。

BridgeInterceptor(桥接拦截器)

请求头 说明
Content-Type 请求体类型(如 application/x-www-form-urlencoded)
Content-Length/Transfer-Encoding 请求体解析方式
Host 请求的主机站点
Connection:Keep-Alive 默认保持长连接
Accept-Encoding:gzip 接受响应体使用gzip压缩
Cookie Cookie 身份识别
User-Agent 用户信息,如操作系统、浏览器等

在补全了请求头后交给下一个拦截器处理,得到响应后,主要干两件事情:

  • 如果使用gzip返回的数据,则使用GzipSource包装便于解析。
  • 保存cookie,在下次请求则会读取对应的数据设置进入请求头,默认的 CookieJar 不提供实现

BridgeInterceptor总结:

对用户构建的 Request 进行添加或者删除相关头部信息,以转化成能够真正进行网络请求的 Request 将符合网络 请求规范的Request交给下一个拦截器处理,并获取 Response 如果响应体经过了GZIP压缩,那就需要解压,再构 建成用户可用的 Response 并返回

CacheInterceptor (缓存拦截器)

只有当互联网可用时才会返回缓存的响应,因为 OkHttp 就是这样设计的。

在进入 OkHttp Core 之前,我们必须拦截 Response 并添加 header(Cache-Control),所以它会被视为响应(带有 Cache-Control header)已经到来来自服务器,OkHttp Core 会尊重并缓存响应。
创建缓存拦截器

public class CacheInterceptor implements Interceptor {
  @Override
  public Response intercept(Chain chain) throws IOException {
    Request request = chain.request();
    Response respOnse= chain.proceed(request);
    String cache = request.header("Cache-Time");
    if (!Util.checkNULL(cache)) {//缓存时间非空
      Response response1 = response.newBuilder()
          .removeHeader("Pragma")
          .removeHeader("Cache-Control")
          //cache for cache seconds
          .header("Cache-Control", "max-age="+cache)
          .build();
      return response1;
    } else {
      return response;
    }
  }
}

配置缓存路径

public class CacheFile {
  Context mContext;
 
  public CacheFile(Context context) {
    mCOntext= context;
  }
 
  public Cache provideCache() {//使用应用缓存文件路径,缓存大小为10MB
    return new Cache(mContext.getCacheDir(), 10 * 1024 * 1024);
  }
}

指定了缓存的大小为10MB。这里如果缓存的数据量大于这个值,内部会使用lur规则进行删除。

使用

OkHttpClient client = new OkHttpClient.Builder()
         .addNetworkInterceptor(new CacheInterceptor())//缓存拦截器
         .cache(new CacheFile(mAppliactionContext).provideCache())//缓存空间提供器
         .connectTimeout(8, TimeUnit.SECONDS)
         .readTimeout(3, TimeUnit.SECONDS)
         .writeTimeout(3, TimeUnit.SECONDS)
         .build();

ConnectInterceptor(链接拦截器)

拦截器中的所有实现都是为了获得一份与目标服务器的连接,在这个连接上进行HTTP数据的收发。

CallServerInterceptor(请求服务拦截器)

CallServerInterceptor完成HTTP协议报文的封装和解析。

addInterceptor与addNetworkInterceptor的区别

二者通常的叫法为应用拦截器和网络拦截器,从整个责任链路来看,应用拦截器是最先执行的拦截器,也就是用户自己设置request属性后的原始请求,而网络拦截器位于ConnectInterceptor和CallServerInterceptor之间,此时网络链路已经准备好,只等待发送请求数据。

首先,应用拦截器在RetryAndFollowUpInterceptor和CacheInterceptor之前,所以一旦发生错误重试或者网络重定向,网络拦截器可能执行多次,因为相当于进行了二次请求,但是应用拦截器永远只会触发一次。另外如果在CacheInterceptor中命中了缓存就不需要走网络请求了,因此会存在短路网络拦截器的情况。
其次,如上文提到除了CallServerInterceptor,每个拦截器都应该至少调用一次realChain.proceed方法。实际上在应用拦截器这层可以多次调用proceed方法(本地异常重试)或者不调用proceed方法(中断),但是网络拦截器这层连接已经准备好,可且仅可调用一次proceed方法。
最后,从使用场景看,应用拦截器因为只会调用一次,通常用于统计客户端的网络请求发起情况;而网络拦截器一次调用代表了一定会发起一次网络通信,因此通常可用于统计网络链路上传输的数据。

你可能感兴趣的:(okhttp,android,拦截器)