okhttp3-源码分析(2) 拦截器链的实现

okhttp3-源码分析(2) 拦截器链的实现,第1张

okhttp3-源码分析(2) 拦截器链的实现

拦截器链(Interceptor)应该是okhttp框架的核心之一。

责任链模式

okhttp的请求拦截器的实现是一种典型的责任链模式,责任链模式一般需要拦截类实现同样的接口。在okhttp中有一个Interceptor接口,默认的拦截器和我们自定义的拦截器都要实现这个接口。Interceptor 接口内部还有一个内部接口Chain。在okhttp中一般使用的是他的具体实现类RealInterceptorChain

下面Interceptor接口的部分代码:

public interface Interceptor {
	//chain里面包含request等对象,通过chain来处理并传递请求
  Response intercept(Chain chain) throws IOException;

  interface Chain {
  	//返回chain所持有的request
    Request request();
	//把request交给下一个拦截器处理
    Response proceed(Request request) throws IOException;
    ........................
  }
}


源码解析

在上一节讲到的重要方法getResponseWithInterceptorChain()的最后一段,我们构建了一个RealInterceptorChain对象,并调用他的proceed()方法来获取Response。

    Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
        originalRequest, this, eventListener, client.connectTimeoutMillis(),
        client.readTimeoutMillis(), client.writeTimeoutMillis());

    return chain.proceed(originalRequest);
    

  public RealInterceptorChain(List 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;
  }

这里是第一次调用proceed方法,把原始的请求传进去,并通知下一个拦截器进行处理。如果我们没有添加自定义的拦截器的话,一般来说,处理request的第一个拦截器会是 RetryAndFollowUpInterceptor,主要作用是构建 StreamAllocation以及完成收到response后的请求重试及重定向工作。
下面直接来看RealInterceptorChain的proceed()方法:

//RealInterceptorChain里面的方法  
  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.
    //调用拦截链中的下一个拦截器,会根据下面这个 next 对象的index参数去取相对应的拦截器
    RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
        connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
        writeTimeout);//注意这个index + 1
    Interceptor interceptor = interceptors.get(index);//根据index取拦截器
      //如果没有自定义拦截器的话,第一个取到的就是重定向拦截器,之后会调用各个interceptor的intercept方法	
    //调用拦截器的intercept方法并获取到返回的response  
    Response response = interceptor.intercept(next);
      
	//下面就是处理返回的response了
      
    // Confirm that the next interceptor made its required call to chain.proceed().
      //确认下一个拦截器确实调用了一次 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.
    //确保返回的response不为null  
    if (response == null) {
      throw new NullPointerException("interceptor " + interceptor + " returned null");
    }
	//response的body也不能为null 
    if (response.body() == null) {
      throw new IllegalStateException(
          "interceptor " + interceptor + " returned a response with no body");
    }

    return response;
  }


//下面是RetryAndFollowUpInterceptor的intercept方法中的部分代码
//可以看到一般在intercept方法中会递归调用proceed方法,把request递给下一个拦截器处
............

      Response response;//返回的response
      boolean releaseConnection = true;
      try {//传入request,并交给
        response = realChain.proceed(request, streamAllocation, null, null);
        releaseConnection = false;
      
      } 
................
总结

在okhttp在初始化一个 RealInterceptorChain 对象后,可以通过调用proceed()方法,传入 RealInterceptorChain 对象,在proceed()方法内,会通过调用拦截器的Intercept的方法,通知下一个拦截器对RealInterceptorChain 对象的属性进行设置(主要是处理request和response)。
(注:RealInterceptorChain 对象有一个名为index的int型变量,正式通过index这个属性,来正确的选择拦截器。比如:index = 0,就表示选择第一个拦截器)
在拦截器的Intercept又会递归调用proceed()方法,把RealInterceptorChain 对象传给下一个对象进行处理。
Intercept方法的工作可以分为两部分,第一部分是在调用proceed()方法前,这部分的任务主要是向服务器发送request前的准备。第二部分是在在调用proceed()方法后,对proceed()方法返回的response(也就是从下面的拦截器传递上来的服务器返回的response)进行处理。
简略流程:

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/5660812.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-16
下一篇 2022-12-16

发表评论

登录后才能评论

评论列表(0条)

保存