美文网首页
OKHTTP 之责任链理解

OKHTTP 之责任链理解

作者: heiheiwanne | 来源:发表于2017-04-07 17:06 被阅读314次

okhttp中一开始以为拦截器使用的是动态代理,类似Spring MVC里面的拦截器,当然okhttp仅仅为底层框架是没必要代理的,不过retrofit 使用的是动态代理,后来翻看源码为责任链加递归调用

拦截器调用顺序

RealCall.java

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)); //最底下是CallServerInterceptor 拦截器

    Interceptor.Chain chain = new RealInterceptorChain(
        interceptors, null, null, null, 0, originalRequest);
    return chain.proceed(originalRequest);
  }
  • 在配置 OkHttpClient 时设置的 interceptors;
  • 负责失败重试以及重定向的 RetryAndFollowUpInterceptor;
  • 负责把用户构造的请求转换为发送到服务器的请求、把服务器返回的 响应转换为用户友好的响应的 BridgeInterceptor;
  • 负责读取缓存直接返回、更新缓存的 CacheInterceptor;
  • 负责和服务器建立连接的 ConnectInterceptor;
  • 配置 OkHttpClient 时设置的 networkInterceptors;
  • 负责向服务器发送请求数据、从服务器读取响应数据的 CallServerInterceptor。

RealInterceptorChain.java

public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
      Connection 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 && !sameConnection(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);
//索引+1 ,这里是使用了RealInterceptorChain的链 进行递归管理的,而不是我们普通上的那种递归,这种使用方式值得考虑,
//这样可以进行一些判断等处理,递归的是类,不是方法,很棒
    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");
    }

    return response;
  }

CacheInterceptor.java


    // If we don't need the network, we're done.
    if (networkRequest == null) {
      return cacheResponse.newBuilder()
          .cacheResponse(stripBody(cacheResponse))
          .build();
    }
    Response networkResponse = null;
    try {
      networkResponse = chain.proceed(networkRequest);  // 此处进行了递归处理
    } finally {
      // If we're crashing on I/O or otherwise, don't leak the cache body.
      if (networkResponse == null && cacheCandidate != null) {
        closeQuietly(cacheCandidate.body());
      }
    }

CallServerInterceptor.java

在最后一个Intercept 里面是直接返回了response 而不是进行继续递归

 httpCodec.finishRequest();

    if (responseBuilder == null) {
      responseBuilder = httpCodec.readResponseHeaders(false);
    }

    Response response = responseBuilder //  这里直接进行了new操作
        .request(request)
        .handshake(streamAllocation.connection().handshake())
        .sentRequestAtMillis(sentRequestMillis)
        .receivedResponseAtMillis(System.currentTimeMillis())
        .build();

    int code = response.code();
    if (forWebSocket && code == 101) {
      // Connection is upgrading, but we need to ensure interceptors see a non-null response body.
      response = response.newBuilder()
          .body(Util.EMPTY_RESPONSE)
          .build();
    } else {
      response = response.newBuilder()
          .body(httpCodec.openResponseBody(response))
          .build();
    }

    if ("close".equalsIgnoreCase(response.request().header("Connection"))
        || "close".equalsIgnoreCase(response.header("Connection"))) {
      streamAllocation.noNewStreams();
    }

    if ((code == 204 || code == 205) && response.body().contentLength() > 0) {
      throw new ProtocolException(
          "HTTP " + code + " had non-zero Content-Length: " + response.body().contentLength());
    }

    return response;

总结:

  • 首先定义拦截器一层层往下运行,直到最底下的拦截器返回response ,一层层往上透传,直到最上层,然后处理一些信息,这个很像事件传递机制,类比下

相关文章

  • OKHTTP 之责任链理解

    okhttp中一开始以为拦截器使用的是动态代理,类似Spring MVC里面的拦截器,当然okhttp仅仅为底层框...

  • Okhttp之责任链

    Okhttp之责任链 Okhttp简介 okhttp是一个第三方类库,用于android中请求网络。这是一个开源项...

  • Okhttp3 Interceptor(三)

    前言 OkHttp 中的 Interceptor 是通过责任链模式来设计的, 责任链模式参考: 责任链模式 , 至...

  • 从OKHttp源码中看责任链模式

    上篇文章简单理解责任链模式只做了Demo,这篇文章就结合OKHttp的框架来具体看看责任链模式,没看过上篇文章的建...

  • 高仿okhttp手写责任链模式

    okhttp使用的设计模式面试的时候经常被问到,其中里面最多的建造者模式和责任链模式其中责任链模式也是okhttp...

  • okhttp网络框架源码浅析(二)

    okhttp网络框架源码浅析(一) interceptors责任链 不清楚责任链设计模式,可以先了解一下责任链设计...

  • OkHttp源码之RetryAndFollowUpInterce

    之前在上一篇文章okhttp源码之责任链模式中有提到过,okhttp的所有功能都是通过拦截器来实现的,就是我们今天...

  • 责任链模式与 OkHttp

    什么是责任链模式 OkHttp中责任链模式的实现 一、什么是责任链模式 使多个对象都有机会处理请求,从而避免了请求...

  • OkHttp设计模式剖析(三)策略模式

    上一篇 OkHttp设计模式剖析(二)责任链模式 下一篇 OkHttp设计模式剖析(四)享元模式 OKHTTP...

  • OkHttp源码之责任链模式

    对于okhttp来说,它的拦截器各位肯定是非常熟悉的,正是由于它的存在,okhttp的扩展性极强,对于调用方来说可...

网友评论

      本文标题:OKHTTP 之责任链理解

      本文链接:https://www.haomeiwen.com/subject/qgbhattx.html