Okhttp源码解析(二)

本文深入剖析Okhttp中的核心设计——拦截器链。详细解释了Okhttp如何通过拦截器链实现网络监听、请求响应重写及失败重试等功能。通过源码分析,揭示了RealInterceptorChain对象如何构建及proceed方法的执行流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Okhttp源码解析(一)

在上一章的结尾我们遗留了一个很重要的方法

Response response = getResponseWithInterceptorChain();

该方法返回的是一个Response对象,相信使用过OkHttp的童鞋对于这个对象应该不陌生,这个就是Http网络请求最终的响应对象。那么getResponseWithInterceptorChain()是如何获取到响应对象的。在分析该方法前我们先来说一下OkHttp中的一个核心设计OkHttp拦截器。

拦截器是什么?

官网:拦截器是OkHttp中提供的一种强大机制,它可以实现网络监听、请求以及响应重写、请求失败重试等功能。

下面我们来看一下拦截器图。
在这里插入图片描述
OkHttp将拦截器分为两部分:

  1. 应用程序拦截器
    这个拦截器是用户自己根据需求来实现的。

  2. 网络拦截器
    这个是由源码提供的。总共有5个拦截器,见下图,具体的作用我们会在稍后进行讲解。
    在这里插入图片描述
    OkHttp实际上是构建了一个强大的拦截器链,将请求中的任务的各个部分进行拦截干预,达到灵活控制的目的,这是我个人的理解。
    而拦截器的实现部分,以及真正的Http的请求以及响应部分都是由这个方法展开的。下面我们就来分析一下该方法,该方法位于源码RealCall类中

Response getResponseWithInterceptorChain() throws IOException {
    // Build a full stack of interceptors.
    List<Interceptor> interceptors = new ArrayList<>();
    //添加用户自己实现的<应用程序拦截器>
    interceptors.addAll(client.interceptors());
    //源码实现的网络拦截器
    interceptors.add(retryAndFollowUpInterceptor);
    interceptors.add(new BridgeInterceptor(client.cookieJar()));
    interceptors.add(new CacheInterceptor(client.internalCache()));
    interceptors.add(new ConnectInterceptor(client));
    if (!forWebSocket) {
      interceptors.addAll(client.networkInterceptors());
    }
    interceptors.add(new CallServerInterceptor(forWebSocket));
    
    //使用List<Interceptor>拦截器集合构建RealInterceptorChain对象
    Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
        originalRequest, this, eventListener, client.connectTimeoutMillis(),
        client.readTimeoutMillis(), client.writeTimeoutMillis());
    
    //调用Interceptor的proceed方法返回Response对象
    return chain.proceed(originalRequest);
  }

最终调用了

    //调用Interceptor的proceed方法返回Response对象
    return chain.proceed(originalRequest);

可以看到Interceptor.Chain是一个接口,那么该方法调用的就是RealInterceptorChain的proceed方法。接下来我们就看一下RealInterceptorChain中的该方法

我们老规矩先上图
在这里插入图片描述

public RealInterceptorChain(List<Interceptor> interceptors, StreamAllocation streamAllocation,
      HttpCodec httpCodec, RealConnection connection, int index, Request request, Call call,
      EventListener eventListener, int connectTimeout, int readTimeout, int writeTimeout) {
    this.interceptors = interceptors;
    this.connection = connection;
    this.streamAllocation = streamAllocation;
    this.httpCodec = httpCodec;
    this.index = index;
    this.request = request;
    this.call = call;
    this.eventListener = eventListener;
    this.connectTimeout = connectTimeout;
    this.readTimeout = readTimeout;
    this.writeTimeout = writeTimeout;
  }
  
@Override public Response proceed(Request request) throws IOException {
    return proceed(request, streamAllocation, httpCodec, connection);
  }

  public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
      RealConnection connection) throws IOException {
    if (index >= interceptors.size()) throw new AssertionError();

    calls++;

    // If we already have a stream, confirm that the incoming request will use it.
    if (this.httpCodec != null && !this.connection.supportsUrl(request.url())) {
      throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
          + " must retain the same host and port");
    }

    // If we already have a stream, confirm that this is the only call to chain.proceed().
    if (this.httpCodec != null && calls > 1) {
      throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
          + " must call proceed() exactly once");
    }

    // Call the next interceptor in the chain.
    RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
        connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
        writeTimeout);
    //interceptors就是之前创建的拦截器集合
    Interceptor interceptor = interceptors.get(index);
    Response response = interceptor.intercept(next);

    // Confirm that the next interceptor made its required call to chain.proceed().
    if (httpCodec != null && index + 1 < interceptors.size() && next.calls != 1) {
      throw new IllegalStateException("network interceptor " + interceptor
          + " must call proceed() exactly once");
    }

    // Confirm that the intercepted response isn't null.
    if (response == null) {
      throw new NullPointerException("interceptor " + interceptor + " returned null");
    }

    if (response.body() == null) {
      throw new IllegalStateException(
          "interceptor " + interceptor + " returned a response with no body");
    }

    return response;
  }

代码量还算可以,这里我们来截取重要代码进行讲解
首先构造方法中

    this.index = index;

然后proceed()方法中

    RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
        connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
        writeTimeout);
    Interceptor interceptor = interceptors.get(index);
    Response response = interceptor.intercept(next);

之前我们在RealCall中的getResponseWithInterceptorChain()方法中通过构造函数创建了一个RealInterceptorChain对象,该对象将index赋值为int的默认值也就是0,然后调用了它的proceed(),而在它的proceed()的方法中又创建了一个新的RealInterceptorChain对象,而该对象使用的是index+1构建的,也就是说新创建的这个对象的index变量是上一个的+1,然后根据构造中的index值为下标,从interceptors拦截器集合中获取之前add进去的拦截器Interceptor对象,然后执行intercept(next)方法,传入新构建的RealInterceptorChain对象next。

设计精髓

通过index+1的方法赋值下一个构建出的RealInterceptorChain对象的index变量,然后从拦截器集合中不断寻找下一个拦截器,这样巧妙的方式,就构成了一个链条,也就是拦截器链,也是设计模式中的责任链模式。

下一篇文章我们就来分析下源码中的各个拦截器

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值