原理-Android 综合

Android okhttp 框架分析

2018-06-02  本文已影响129人  高丕基

1、概述

okhttp是一个第三方类库,用于android中请求网络。同时这是一个开源项目,用来替代HttpUrlConnection和HttpClient。

okhttp的源码地址在github上为:okhttp源码地址

okhttp的官网地址:okhttp官网地址

其一个简单的异步调用方法如下:


private final OkHttpClient client = new OkHttpClient();

  public void run() throws Exception {

    Request request = new Request.Builder()

        .url("http://publicobject.com/helloworld.txt")

        .build();

    client.newCall(request).enqueue(new Callback() {

      @Override public void onFailure(Call call, IOException e) {

        e.printStackTrace();

      }

      @Override public void onResponse(Call call, Response response) throws IOException {

        if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);

        Headers responseHeaders = response.headers();

        for (int i = 0, size = responseHeaders.size(); i < size; i++) {

          System.out.println(responseHeaders.name(i) + ": " + responseHeaders.value(i));

        }

        System.out.println(response.body().string());

      }

    });

  }

每一个HTTP请求中都包含一个URL,一个方法(如GETPOST),和一个请求头列表(headers)。请求还可以含有一个请求体(body):一个特定内容类型的数据流。

每一个HTTP响应中都包含一个状态码(如200代表成功,404代表未找​​到),一个响应头列表(headers)和一个可选的响应体(body)。

更多的okhttp用法可以参考其官方Wiki:okhttp Wiki

2、框架及源码分析

okhttp的整个流程如下图所示:

流程图

从这个流程图可以看出okhttp的整个请求与响应的流程就是Dispatcher不断从Request Queue里取出请求(Call),然后通过拦截器Interceptor一层层向下传递进行请求,获取到响应后再一层层通过拦截器Interceptor传回来。

其具体的函数调用链如下所示:

函数调用链

接下来我们具体分析一下各个相关的类及其核心函数。

2.1 OkHttpClient

OkHttpClient是整个okhttp的入口,创建它有两种方式:


OkHttpClient client =new OkHttpClient();

OkHttpClient client = new OkHttpClient.Builder()

                    .build();

其实第一种直接new的方式内部也是由一个建造出完成其初始化的


// OkHttpClient.class

public OkHttpClient() {

    this(new Builder());

  }

来看一下其真正构造方式:


// OkHttpClient.class

OkHttpClient(Builder builder) {

    // 分发器Dispatcher对象,记录请求执行情况,内部维护一个线程池执行异步请求

    this.dispatcher = builder.dispatcher; 

    // 代理设置,配置代理类型(直连,HTTP代理,Socket代理)以及Socket地址

    this.proxy = builder.proxy;

    // 协议集合,默认协议集合包括HTTP2,HTTP_1_1

    this.protocols = builder.protocols;

    // 连接规范,指定Socket连接的配置

    this.connectionSpecs = builder.connectionSpecs;

    // 应用拦截器集合

    this.interceptors = Util.immutableList(builder.interceptors);

    // 网络拦截器集合

    this.networkInterceptors = Util.immutableList(builder.networkInterceptors);

    // 事件监听器工厂

    this.eventListenerFactory = builder.eventListenerFactory;

    // 代理选择器

    this.proxySelector = builder.proxySelector;

    // Cookie瓶,为HTTP的cookies提供策略和持久化

    this.cookieJar = builder.cookieJar;

    // 磁盘缓存,内部使用DiskLruCache实现

    this.cache = builder.cache;

    // okhttp内部缓存,应用层不感知其存在

    this.internalCache = builder.internalCache;

    // socket工厂类

    this.socketFactory = builder.socketFactory;

    // HTTPs相关成员变量

    ...

    // 连接池

    this.connectionPool = builder.connectionPool;

    // DNS

    this.dns = builder.dns;

    // 是否跟随SSL重定向

    this.followSslRedirects = builder.followSslRedirects;

    // 是否跟随重定向

    this.followRedirects = builder.followRedirects;

    // 连接失败是否重试

    this.retryOnConnectionFailure = builder.retryOnConnectionFailure;

    // 连接超时时间

    this.connectTimeout = builder.connectTimeout;

    // 读超时时间

    this.readTimeout = builder.readTimeout;

    // 写超时时间

    this.writeTimeout = builder.writeTimeout;

    // ping间隔时长

    this.pingInterval = builder.pingInterval;

  }

从其构造函数不难看出,该类可以让用户配置各种想配置的参数,从而实现个性化的请求。

OkHttpClient类里面有一个几乎一定会调用的方法:public Call newCall(Request request) 我们进入到里面看一下:


@Override public Call newCall(Request request) {

    return new RealCall(this, request, false /* for web socket */);

  }

这一方法传入了一个Request的请求体,并最终输出一个RealCall。

2.2 Request

Request是用户设置的请求体,其在构建时也使用了建造者模式:


// Request.class

Request(Builder builder) {

    // 请求url

    this.url = builder.url;

    // 请求方法

    this.method = builder.method;

    // 请求头

    this.headers = builder.headers.build();

    // 请求体

    this.body = builder.body;

    // 给该请求设置一个标志,用于可根据标志取消某一类请求

    this.tag = builder.tag != null ? builder.tag : this;

  }

同时可以对该请求配置单独的缓存策略:


// Request.class

public Builder cacheControl(CacheControl cacheControl) {

      String value = cacheControl.toString();

      if (value.isEmpty()) return removeHeader("Cache-Control");

      return header("Cache-Control", value);

    }

2.3 Call 和 RealCall

2.1节最后调用的newCall()方法里面构建了一个RealCall(),而该方法返回的是Call 。可以断定两者是一对抽象和具体实现。我们先看一下Call,它是一个接口类:


// Call.class

public interface Call extends Cloneable {

  //返回当前请求

  Request request();

  //同步请求方法,此方法会阻塞当前线程知道请求结果放回

  Response execute() throws IOException;

  //异步请求方法,此方法会将请求添加到队列中,然后等待请求返回

  void enqueue(Callback responseCallback);

  //取消请求

  void cancel();

  //请求是否在执行,当execute()或者enqueue(Callback responseCallback)执行后该方法返回true

  boolean isExecuted();

  //请求是否被取消

  boolean isCanceled();

  //创建一个新的一模一样的请求

  Call clone();

  interface Factory {

    Call newCall(Request request);

  }

}

这个Call 里面定义了一些关于请求的方法,同时内部有一个接口子类,其内部有我们熟悉的newCall()方法。而这个子接口就是由OkHttpClient继承而实现的。接下来看一下Call 的具体实现类RealCall的构造方法:


// RealCall.class

final class RealCall implements Call {

  private RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {

    //我们构建的OkHttpClient,用来传递参数

    this.client = client;

    this.originalRequest = originalRequest;

    //是不是WebSocket请求,WebSocket是用来建立长连接的。

    this.forWebSocket = forWebSocket;

    //构建RetryAndFollowUpInterceptor拦截器

    this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);

  }

}

这里面除了将参数传入参数赋值给成员变量,同时初始化了我们在上面提到的第一个拦截器RetryAndFollowUpInterceptor。关于拦截器之后会详细说明。

当我们创建出Call 之后一般会调用其execute()方法或者enqueue(Callback responseCallback)方法来发起请求的调用。同时这两个方法也是真正请求开始的入口。

① 同步请求 execute()


// RealCall.class

@Override public Response execute() throws IOException {

    // 判断该请求是否已经被执行过,即一个请求只能被执行一次

      synchronized (this) {

        if (executed) throw new IllegalStateException("Already Executed");

        executed = true;

      }

        ...

      try {

        // 交由Dispatcher处理请求

        client.dispatcher().executed(this);

        // 获取请求结果

        Response result = getResponseWithInterceptorChain();

        if (result == null) throw new IOException("Canceled");

        return result;

      } finally {

        client.dispatcher().finished(this);

      }

    }

② 异步请求


// RealCall.class

@Override public void enqueue(Callback responseCallback) {

         // 判断该请求是否已经被执行过,即一个请求只能被执行一次

        synchronized (this) {

          if (executed) throw new IllegalStateException("Already Executed");

          executed = true;

        }

        ...

         // 交由Dispatcher处理请求

        client.dispatcher().enqueue(new AsyncCall(responseCallback));

      }

从上面实现可以看出,不管是同步请求还是异步请求都是Dispatcher在处理:

同步请求:直接执行,并返回请求结果

异步请求:构造一个AsyncCall,并将自己加入处理队列中。

AsyncCall本质上是一个Runable,Dispatcher会调度ExecutorService来执行这些Runable。同时AsyncCall 是RealCall的内部类,所以它可以调用RealCall的成员变量。这边重点关注一下其执行函数execute(),该函数在其父类NamedRunnable 的run()中执行。


// RealCall.class

final class AsyncCall extends NamedRunnable {

    private final Callback responseCallback;

    AsyncCall(Callback responseCallback) {

      super("OkHttp %s", redactedUrl());

      this.responseCallback = responseCallback;

    }

    ...

    @Override protected void execute() {

      boolean signalledCallback = false;

      try {

        // 获取请求结果

        Response response = getResponseWithInterceptorChain();

        if (retryAndFollowUpInterceptor.isCanceled()) {

        // 如果请求已经被取消,回调失败接口

          signalledCallback = true;

          responseCallback.onFailure(RealCall.this, new IOException("Canceled"));

        } else {

        // 不然就回调请求成功接口将请求结果回调出去

          signalledCallback = true;

          responseCallback.onResponse(RealCall.this, response);

        }

      } catch (IOException e) {

        if (signalledCallback) {

          // 只接受一次请求结果

          Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e);

        } else {

            // 获取请求是抛出异常,回调失败接口,并将异常回调回去

          responseCallback.onFailure(RealCall.this, e);

        }

      } finally {

        // 关闭dispatcher

        client.dispatcher().finished(this);

      }

    }

  }

从上面代码可以看出,不管是同步请求还是异步请求最后都会通过getResponseWithInterceptorChain()获取Response,只不过异步请求多了个线程调度,异步执行的过程。关于这个方法我们一会详细分析,先看一下Dispatcher这个类。

2.4 Dispatcher


// Dispatcher.class

public final class Dispatcher {

// 最大请求数

 private int maxRequests = 64;

// 每个主机最大请求数

 private int maxRequestsPerHost = 5;

...

// 线程池

 private @Nullable ExecutorService executorService;

// 准备运行的异步请求

 private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();

// 正在运行的异步请求

 private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();

// 正在运行的同步请求

 private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();

 synchronized void executed(RealCall call) {

        // 将同步请求加入正在运行的同步请求队列

        runningSyncCalls.add(call);

      }

      synchronized void enqueue(AsyncCall call) {

      //正在运行的异步请求不得超过64,同一个host下的异步请求不得超过5个

      if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {

        // 将异步请求加入正在运行的异步请求队列

        runningAsyncCalls.add(call);

        // 执行该异步请求

        executorService().execute(call);

      } else {

         // 将异步请求加入准备运行的异步请求队列

        readyAsyncCalls.add(call);

      }

    }

}

Dispatcher是一个任务调度器,它内部维护了三个双端队列:

readyAsyncCalls:准备运行的异步请求

runningAsyncCalls:正在运行的异步请求

runningSyncCalls:正在运行的同步请求

同步请求就直接把请求添加到正在运行的同步请求队列runningSyncCalls中,异步请求会做个判断:如果正在运行的异步请求不超过64,而且同一个host下的异步请求不得超过5个则将请求添加到正在运行的同步请求队列中runningAsyncCalls并开始执行请求,否则就添加到readyAsyncCalls继续等待。

2.5 Interceptor

讲完Dispatcher里的实现,继续来看getResponseWithInterceptorChain()的实现,这个方法才是真正发起请求并处理请求的地方。


    //RealCall.class

     Response getResponseWithInterceptorChain() throws IOException {

        // Build a full stack of interceptors. List interceptors = new ArrayList<>();

        //自定义的Interceptor

        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));

        // 开始获取第一个拦截器的拦截链

        Interceptor.Chain chain = new RealInterceptorChain(

            interceptors, null, null, null, 0, originalRequest);

        // 开始链式执行各个拦截器

        return chain.proceed(originalRequest);

      }

这几行代码,完成了对请求的所有处理过程,Interceptor将网络请求、缓存、透明压缩等功能统一了起来,它的实现采用责任链模式,各司其职,每个功能都是一个Interceptor,上一级处理完成以后传递给下一级,它们最后连接成了一个Interceptor.Chain。它们的功能如下:

RetryAndFollowUpInterceptor:负责重定向。

BridgeInterceptor:负责把用户构造的请求转换为发送给服务器的请求,把服务器返回的响应转换为对用户友好的响应。

CacheInterceptor:负责读取缓存以及更新缓存。

ConnectInterceptor:负责与服务器建立连接。

CallServerInterceptor:负责从服务器读取响应的数据。

位置决定功能,位置靠前的先执行,最后一个则负责与服务器通讯,请求从RetryAndFollowUpInterceptor开始层层传递到CallServerInterceptor,每一层都对请求做相应的处理,处理的结构再从CallServerInterceptor层层返回给RetryAndFollowUpInterceptor,最后请求的发起者获得了服务器返回的结果。以上便是Okhttp整个请求与响应的具体流程,可以发现拦截器才是Okhttp核心功能所在。

先看一下拦截器的接口类Interceptor:


public interface Interceptor {

  Response intercept(Chain chain) throws IOException;

  interface Chain {

    Request request();

    Response proceed(Request request) throws IOException;

    // 返回请求将在其上执行。只网络连接拦截器实现该方法

    @Nullable Connection connection();

  }

}

这个接口类只有一个方法和一个Chain 内部接口类。而这个Chain 的实现类为上面getResponseWithInterceptorChain() 方法里面看到的RealInterceptorChain:


public final class RealInterceptorChain implements Interceptor.Chain {

// 拦截器集合

 private final Listinterceptors;

// 流分配器

 private final StreamAllocation streamAllocation;

// http编解码器

 private final HttpCodec httpCodec;

// 连接对象

 private final RealConnection connection;

// 目前调用的拦截器集合里面的拦截器位置

 private final int index;

// 请求体

 private final Request request;

// 该请求调用次数

 private int calls;

 public RealInterceptorChain(List interceptors, StreamAllocation streamAllocation,

      HttpCodec httpCodec, RealConnection connection, int index, Request request) {

    this.interceptors = interceptors;

    this.connection = connection;

    this.streamAllocation = streamAllocation;

    this.httpCodec = httpCodec;

    this.index = index;

    this.request = request;

  }

    ...

  public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,

      RealConnection connection) throws IOException {

    if (index >= interceptors.size()) throw new AssertionError();

    calls++;

    // 如果我们已经有一个流,请确认传入的请求将使用它。

    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");

    }

    // 如果我们已经有一个流,请确认这是对chain.proceed()的唯一调用。

    // 也就是说每一个RealInterceptorChain ,proceed()只能调用一次

    if (this.httpCodec != null && calls > 1) {

      throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)

          + " must call proceed() exactly once");

    }

    // 调用链中的下一个拦截器。

    RealInterceptorChain next = new RealInterceptorChain(

        interceptors, streamAllocation, httpCodec, connection, index + 1, request);

    Interceptor interceptor = interceptors.get(index);

    // 获取响应体

    Response response = interceptor.intercept(next);

    // 确认下一个拦截器对chain.proceed()进行了必要的调用。

    if (httpCodec != null && index + 1 < interceptors.size() && next.calls != 1) {

      throw new IllegalStateException("network interceptor " + interceptor

          + " must call proceed() exactly once");

    }

    // 确认拦截器的响应不为空。

    if (response == null) {

      throw new NullPointerException("interceptor " + interceptor + " returned null");

    }

    return response;

  }

}

有上面的代码可以看出,RealInterceptorChain 在调用proceed方法之后,会继续构建一个新的RealInterceptorChain对象,调用下一个interceptor来继续请求,直到所有interceptor都处理完毕,将得到的response返回。

同时每个interceptor的intercept()方法基本都遵循以下规则:


// interceptor.class 的子类

@Override public Response intercept(Chain chain) throws IOException {

     Request request = chain.request();

    //1 Request阶段,该拦截器在Request阶段负责做的事情

    //2 调用RealInterceptorChain.proceed(),其实是在递归调用下一个拦截器的intercept()方法

    response = ((RealInterceptorChain) chain).proceed(request, streamAllocation, httpCodec, connection);

    //3 Response阶段,完成了该拦截器在Response阶段负责做的事情,然后返回到上一层的拦截器。

    return response;   

    }

  }

也就是说对于每个Request按照顺序正向一步步对其进行包装处理。而对于Response则是逆向处理的。而各个拦截器的顺序已经在getResponseWithInterceptorChain()中按照add的先后顺序排列好了。接下来按照其顺序一个个分析各个拦截器。

2.5.1 RetryAndFollowUpInterceptor

这个拦截器主要负责失败重试和重定向


public final class RetryAndFollowUpInterceptor implements Interceptor {

    private static final int MAX_FOLLOW_UPS = 20;

    ...

    @Override public Response intercept(Chain chain) throws IOException {

        Request request = chain.request();

        ...

        // 重定向次数

        int followUpCount = 0;

        Response priorResponse = null;

        while (true) {

        ...

          Response response = null;

          boolean releaseConnection = true;

          try {

            // 继续执行下一个Interceptor,即BridgeInterceptor,获取响应

            response = ((RealInterceptorChain) chain).proceed(request, streamAllocation, null, null);

            releaseConnection = false;

          } catch (RouteException e) {

            // 抛出异常,则检测连接是否还可以继续。可以的话就重新进行请求

            if (!recover(e.getLastConnectException(), false, request)) {

              throw e.getLastConnectException();

            }

            releaseConnection = false;

            continue;

          } catch (IOException e) {

            // 和服务端建立连接失败

            boolean requestSendStarted = !(e instanceof ConnectionShutdownException);

            if (!recover(e, requestSendStarted, request)) throw e;

            releaseConnection = false;

            continue;

          } finally {

            //检测到其他未知异常,则释放连接和资源

            if (releaseConnection) {

              streamAllocation.streamFailed(null);

              streamAllocation.release();

            }

          }

          //构建响应体,这个响应体的body为空。

          if (priorResponse != null) {

            response = response.newBuilder()

                .priorResponse(priorResponse.newBuilder()

                        .body(null)

                        .build())

                .build();

          }

          //获取重定向的请求

          Request followUp = followUpRequest(response);

           // 如果重定向请求为null,直接返回结果

          if (followUp == null) {

            if (!forWebSocket) {

              streamAllocation.release();

            }

            return response;

          }

        ...

         //重定向的次数不能超过20次

          if (++followUpCount > MAX_FOLLOW_UPS) {

            streamAllocation.release();

            throw new ProtocolException("Too many follow-up requests: " + followUpCount);

          }

        ...

        // 将请求重新赋值为重定向的请求,继续循环

          request = followUp;

          priorResponse = response;

        }

      }

}

这个拦截器的整个流程可以概括为如下过程:

① 执行下一个Interceptor,即BridgeInterceptor

② 抛出异常,则检测连接是否还可以继续,如果可以的话就进行重试

③ 根据响应码处理请求,返回Request不为空时则进行重定向处理,重定向的次数不能超过20次。如果需要重定向则继续循环请求。

2.5.2 BridgeInterceptor

这个拦截器负责把用户构造的请求转换为发送给服务器的请求,把服务器返回的响应转换为对用户友好的响应。 转换的过程就是添加一些服务端需要的header信息。


public final class BridgeInterceptor implements Interceptor {

  private final CookieJar cookieJar;

  @Override public Response intercept(Chain chain) throws IOException {

    // 获取用户请求

    Request userRequest = chain.request();

    // 真正发送的网络请求构建者,也就是对前面RetryAndFollowUpInterceptor传来的请求进行包装后的请求

    Request.Builder requestBuilder = userRequest.newBuilder();

    // 对请求头进行一些设置

    // 包括:Content-Type、Content-Length、Transfer-Encoding、Host、Connection、Accept-Encoding

    //            Cookie、User-Agent

    ...

    // 执行下一个拦截器,把处理过后的请求放进去

    Response networkResponse = chain.proceed(requestBuilder.build());

    ...

    // 对获取的响应进行处理

    Response.Builder responseBuilder = networkResponse.newBuilder()

        .request(userRequest);

    //判断服务器是否支持gzip压缩,如果支持,则将压缩提交给Okio库来处理

    if (transparentGzip

        && "gzip".equalsIgnoreCase(networkResponse.header("Content-Encoding"))

        && HttpHeaders.hasBody(networkResponse)) {

      GzipSource responseBody = new GzipSource(networkResponse.body().source());

      Headers strippedHeaders = networkResponse.headers().newBuilder()

          .removeAll("Content-Encoding")

          .removeAll("Content-Length")

          .build();

      responseBuilder.headers(strippedHeaders);

      responseBuilder.body(new RealResponseBody(strippedHeaders, Okio.buffer(responseBody)));

    }

    // 返回处理过后的响应

    return responseBuilder.build();

  }

}

2.5.3 CacheInterceptor

这个拦截器负责处理与缓存相关的事情,在这里读取和更新缓存。网络请求到了这个拦截器,会先查找有没对应的缓存,有就直接返回缓存中数据。如果没有,就接着调用下一个拦截器来获取响应,并将响应存到缓存中,方便下一次使用。


public final class CacheInterceptor implements Interceptor {

    @Override public Response intercept(Chain chain) throws IOException {

        // 读取候选缓存

        Response cacheCandidate = cache != null

            ? cache.get(chain.request())

            : null;

        ...

        // 创建缓存策略,强制缓存、对比缓存等

        CacheStrategy strategy = new CacheStrategy.Factory(now, chain.request(), cacheCandidate).get();

        Request networkRequest = strategy.networkRequest;

        Response cacheResponse = strategy.cacheResponse;

        ...

        // 根据策略,不使用网络,又没有缓存的直接报错,并返回错误码504。

        if (networkRequest == null && cacheResponse == null) {

          return new Response.Builder()

              .request(chain.request())

              .protocol(Protocol.HTTP_1_1)

              .code(504)

              .message("Unsatisfiable Request (only-if-cached)")

              .body(Util.EMPTY_RESPONSE)

              .sentRequestAtMillis(-1L)

              .receivedResponseAtMillis(System.currentTimeMillis())

              .build();

        }

        //  根据策略,不使用网络,有缓存的直接返回。

        if (networkRequest == null) {

          return cacheResponse.newBuilder()

              .cacheResponse(stripBody(cacheResponse))

              .build();

        }

        Response networkResponse = null;

        try {

          // 前面两个都没有返回,继续执行下一个Interceptor,即ConnectInterceptor。

          networkResponse = chain.proceed(networkRequest);

        } finally {

          //如果发生IO异常,则释放掉缓存

          if (networkResponse == null && cacheCandidate != null) {

            closeQuietly(cacheCandidate.body());

          }

        }

        //  接收到网络结果,如果响应code式304,则使用缓存,返回缓存结果。

        if (cacheResponse != null) {

          if (networkResponse.code() == HTTP_NOT_MODIFIED) {

            Response response = cacheResponse.newBuilder()

                .headers(combine(cacheResponse.headers(), networkResponse.headers()))

                .sentRequestAtMillis(networkResponse.sentRequestAtMillis())

                .receivedResponseAtMillis(networkResponse.receivedResponseAtMillis())

                .cacheResponse(stripBody(cacheResponse))

                .networkResponse(stripBody(networkResponse))

                .build();

            ...

            return response;

          } else {

            closeQuietly(cacheResponse.body());

          }

        }

        //  读取网络结果。

        Response response = networkResponse.newBuilder()

            .cacheResponse(stripBody(cacheResponse))

            .networkResponse(stripBody(networkResponse))

            .build();

        // 对数据进行缓存。

        if (cache != null) {

          if (HttpHeaders.hasBody(response) && CacheStrategy.isCacheable(response, networkRequest)) {

            CacheRequest cacheRequest = cache.put(response);

            return cacheWritingResponse(cacheRequest, response);

          }

          if (HttpMethod.invalidatesCache(networkRequest.method())) {

            try {

              cache.remove(networkRequest);

            } catch (IOException ignored) {

            }

          }

        }

        // 返回网络读取的结果。

        return response;

      }

}

2.5.4 ConnectInterceptor

该拦截器主要作用是给网络请求提供一个连接,为下一个拦截器做准备。


public final class ConnectInterceptor implements Interceptor {

      @Override public Response intercept(Chain chain) throws IOException {

        RealInterceptorChain realChain = (RealInterceptorChain) chain;

        Request request = realChain.request();

        StreamAllocation streamAllocation = realChain.streamAllocation();

        boolean doExtensiveHealthChecks = !request.method().equals("GET");

        // 获取一个http编解码器,创建输出流。

        HttpCodec httpCodec = streamAllocation.newStream(client, doExtensiveHealthChecks);

        // 获取一个连接对象,负责发起与服务器的连接

        RealConnection connection = streamAllocation.connection();

        // 执行下一个拦截器

        return realChain.proceed(request, streamAllocation, httpCodec, connection);

      }

}

2.5.5 CallServerInterceptor

这是最后一个拦截器,负责真正与服务器进行交互。


public final class CallServerInterceptor implements Interceptor {

    @Override public Response intercept(Chain chain) throws IOException {

        //这些对象在前面的Interceptor都已经创建完毕

        RealInterceptorChain realChain = (RealInterceptorChain) chain;

        HttpCodec httpCodec = realChain.httpStream();

        StreamAllocation streamAllocation = realChain.streamAllocation();

        RealConnection connection = (RealConnection) realChain.connection();

        Request request = realChain.request();

        long sentRequestMillis = System.currentTimeMillis();

        // 写入请求头

        httpCodec.writeRequestHeaders(request);

        Response.Builder responseBuilder = null;

        if (HttpMethod.permitsRequestBody(request.method()) && request.body() != null) {

          if ("100-continue".equalsIgnoreCase(request.header("Expect"))) {

            httpCodec.flushRequest();

            responseBuilder = httpCodec.readResponseHeaders(true);

          }

          // 写入请求体

          if (responseBuilder == null) {

            // Write the request body if the "Expect: 100-continue" expectation was met.

            Sink requestBodyOut = httpCodec.createRequestBody(request, request.body().contentLength());

            BufferedSink bufferedRequestBody = Okio.buffer(requestBodyOut);

            request.body().writeTo(bufferedRequestBody);

            bufferedRequestBody.close();

          } else if (!connection.isMultiplexed()) {

            // If the "Expect: 100-continue" expectation wasn't met, prevent the HTTP/1 connection from

            // being reused. Otherwise we're still obligated to transmit the request body to leave the

            // connection in a consistent state.

            streamAllocation.noNewStreams();

          }

        }

        // 发起网络请求

        httpCodec.finishRequest();

        // 读取响应头

        if (responseBuilder == null) {

          responseBuilder = httpCodec.readResponseHeaders(false);

        }

        Response response = responseBuilder

            .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();

        }

        ...

       // 返回网络响应结果

        return response;

      }

}

这个拦截器将前面准备好的请求头和请求体整合好,向服务器发起网络请求,并获取响应头和响应体返回。

整个请求响应过程到此告一段落。

上一篇下一篇

猜你喜欢

热点阅读