OkHttp面试之--HttpEngine中的sendRequest方法详解

上一节我们介绍了OkHttp网络异步请求的整个流程。其中在流程的最后阶段,我们发现最终创建了HttpEngine对象,并分别调用的此对象的sendRequest和readResponse方法。这两个方法 分别有它相应的作用。这一节我们着重来分析sendRequest流程。

以下是sendRequest的整个方法中的内容:

public void sendRequest() throws RequestException, RouteException, IOException {
    if (cacheStrategy != null) return; // Already sent.
    if (httpStream != null) throw new IllegalStateException();

    Request request = networkRequest(userRequest);

    InternalCache responseCache = Internal.instance.internalCache(client);
    Response cacheCandidate = responseCache != null
        ? responseCache.get(request)
        : null;
    long now = System.currentTimeMillis();
    cacheStrategy = new CacheStrategy.Factory(now, request, cacheCandidate).get();
    networkRequest = cacheStrategy.networkRequest;
    cacheResponse = cacheStrategy.cacheResponse;

    if (responseCache != null) {
      responseCache.trackResponse(cacheStrategy);
    }

    if (cacheCandidate != null && cacheResponse == null) {
      closeQuietly(cacheCandidate.body()); // The cache candidate wasn‘t applicable. Close it.
    }

    // If we‘re forbidden from using the network and the cache is insufficient, fail.
    if (networkRequest == null && cacheResponse == null) {
      userResponse = new Response.Builder()
          .request(userRequest)
          .priorResponse(stripBody(priorResponse))
          .protocol(Protocol.HTTP_1_1)
          .code(504)
          .message("Unsatisfiable Request (only-if-cached)")
          .body(EMPTY_BODY)
          .build();
      return;
    }

    // If we don‘t need the network, we‘re done.
    if (networkRequest == null) {
      userResponse = cacheResponse.newBuilder()
          .request(userRequest)
          .priorResponse(stripBody(priorResponse))
          .cacheResponse(stripBody(cacheResponse))
          .build();
      userResponse = unzip(userResponse);
      return;
    }

    // We need the network to satisfy this request. Possibly for validating a conditional GET.
    boolean success = false;
    try {
      httpStream = connect();
      httpStream.setHttpEngine(this);

      if (writeRequestHeadersEagerly()) {
        long contentLength = OkHeaders.contentLength(request);
        if (bufferRequestBody) {
          if (contentLength > Integer.MAX_VALUE) {
            throw new IllegalStateException("Use setFixedLengthStreamingMode() or "
                + "setChunkedStreamingMode() for requests larger than 2 GiB.");
          }

          if (contentLength != -1) {
            // Buffer a request body of a known length.
            httpStream.writeRequestHeaders(networkRequest);
            requestBodyOut = new RetryableSink((int) contentLength);
          } else {
            // Buffer a request body of an unknown length. Don‘t write request headers until the
            // entire body is ready; otherwise we can‘t set the Content-Length header correctly.
            requestBodyOut = new RetryableSink();
          }
        } else {
          httpStream.writeRequestHeaders(networkRequest);
          requestBodyOut = httpStream.createRequestBody(networkRequest, contentLength);
        }
      }
      success = true;
    } finally {
      // If we‘re crashing on I/O or otherwise, don‘t leak the cache body.
      if (!success && cacheCandidate != null) {
        closeQuietly(cacheCandidate.body());
      }
    }
  }

可以看到sendRequest方法比较长,我对它进行分块解析。其中主要分以下两大块

1 先从 Cache 中判断当前请求是否可以从缓存中返回

2 如果没有Cache则连接网络

先来看下connect方法中是如何创建HttpStream对象的

调用SteamAllocation.newStream的方法创建HttpStream对象并返回。点进去代码如下所示:

从上图中可以看出,在newStream方法中先通过findHealthyConnection方法获取一个RealConnection对象,实际上就是查找可用的Socket对象。在OkHttp框架中有一个特点就是OkHttp可以使用一个Socket对象来维护拥有过个ip的Server端,对于Socket的实现后续再单独讲解,此处不再做介绍。

获取RealConnction对象之后,根据此对象再获取相应的HttpStream对象,我们一般返回的是Http1xStream对象,最后将resultStream赋值给全局变量stream。而这个全局变量会再下一节readResponse方法中再使用。

注意:本节主要对于sendRequest方法中比较核心的代码进行的跟踪分析,在此方法中还有对Request请求的Head和Body的添加操作并没有进行详细描述。感兴趣的同学可以自行研究。

下一节继续讲解HttpEngine.readResponse方法的流程

时间: 2024-12-19 11:11:48

OkHttp面试之--HttpEngine中的sendRequest方法详解的相关文章

Java中的main()方法详解

在Java中,main()方法是Java应用程序的入口方法,也就是说,程序在运行的时候,第一个执行的方法就是main()方法,这个方法和其他的方法有很大的不同,比如方法的名字必须是main,方法必须是public static void 类型的,方法必须接收一个字符串数组的参数等等. 在看Java中的main()方法之前,先看一个最简单的Java应用程序HelloWorld,我将通过这个例子说明Java类中main()方法的奥秘,程序的代码如下: 1 /** 2 * Java中的main()方法

IOS问题汇总:2015-1-9 IOS之NSArray 中调用的方法详解(转)

IOS之NSArray 中调用的方法详解 下面的例子以 NSArray *array = [NSArray arrayWithObjects:@“wendy”,@“andy”,@“tom”,@“jonery”,@“stany”, nil];1.获取数组中总共有多少个对象. -(NSUInteger)count; NSLog(@“%d”,[array count]); 2 2.获取数组中下标对应的元素对象.(下标是从0开始) -(id)objectAtIndex:(NSUInteger)index

java中System.getProperty()方法详解

java中System.getProperty()方法详解,如下: System.out.println("java版本号:" + System.getProperty("java.version")); // java版本号 System.out.println("Java提供商名称:" + System.getProperty("java.vendor")); // Java提供商名称 System.out.println

Python中格式化format()方法详解

Python中格式化format()方法详解 Python中格式化输出字符串使用format()函数, 字符串即类, 可以使用方法; Python是完全面向对象的语言, 任何东西都是对象; 字符串的参数使用{NUM}进行表示,0, 表示第一个参数,1, 表示第二个参数, 以后顺次递加; 使用":", 指定代表元素需要的操作, 如":.3"小数点三位, ":8"占8个字符空间等; 还可以添加特定的字母, 如: 'b' - 二进制. 将数字以2为基数

OkHttp面试之--HttpEngine中的readResponse流程简介

上一节主要大体看了一下sendRequest的流程,本节来看一下当请求发送出去之后,是如果读取请求体中的数据的,具体的代码都在HttpEngine.readResponse方法中,代码如下: public void readResponse() throws IOException { if (userResponse != null) { return; // Already ready. } if (networkRequest == null && cacheResponse ==

IOS5中的新增方法详解

苹果在 iOS5 中给 UIViewController 新增加的 5 方法以及一个属性: addChildViewController: removeFromParentViewController:transitionFromViewController:toViewController:duration:options:animations:completion: willMoveToParentViewController: didMoveToParentViewController:/

C#中的扩展方法详解

“扩展方法使您能够向现有类型“添加”方法,而无需创建新的派生类型.重新编译或以其他方式修改原始类型.”这是msdn上说的,也就是你可以对String,Int,DataRow,DataTable等这些类型的基础上增加一个或多个方法,使用时不需要去修改或编译类型本身的代码. 扩展方法使你能够向现有类型“添加”方法,而无需创建新的派生类型.重新编译或以其他方式修改原始类型. 扩展方法是一种特殊的静态方法,但可以像扩展类型上的实例方法一样进行调用. 以上是msdn官网对扩展方法的描述,现在我通过一个情景

jquery中的ajax方法详解

定义和用法ajax() 方法通过 HTTP 请求加载远程数据.该方法是 jQuery 底层 AJAX 实现.简单易用的高层实现见 $.get, $.post 等.$.ajax() 返回其创建的 XMLHttpRequest 对象.大多数情况下你无需直接操作该函数,除非你需要操作不常用的选项,以获得更多的灵活性.最简单的情况下,$.ajax() 可以不带任何参数直接使用.注意:所有的选项都可以通过 $.ajaxSetup() 函数来全局设置. 语法 jQuery.ajax([settings])

java入门学习:Java中的main()方法详解

本文来源:http://www.zretc.com/technologyDetail/445.html 在Java入门学习中,main()方法是Java应用程序的入口方法,也就是说,程序在运行的时候,第一个执行的方法就是main()方法,这个方法和其他的方法有很大的不同,比如方法的名字必须是main,方法必须是public static void 类型的,方法必须接收一个字符串数组的参数等等. 在看Java中的main()方法之前,先看一个最简单的Java应用程序HelloWorld,我将通过这