Okhttp解析(二)网络请求的执行

上节我们讲解了Okhttp的简单介绍,请求任务的分发,以及请求响应的拦截。现在我们分析数据的请求是如何进行的。

在阅读http请求数据之前,你可能需要了解http和tcp相关的知识。

http原理

http://www.jianshu.com/p/2efddfaea9c3

http://www.jianshu.com/p/26095e423da0

https原理

http://www.jianshu.com/p/33feb2fadb15

TCP/IP详解

http://www.jianshu.com/p/116ebf3034d9

本节主要介绍以下内容

数据的请求响应大致流程

发送请求的过程

读取响应的过程

输出请求头

输出请求体

数据的请求响应大致流程

数据的请求响应操作,是从RealCall的getResponse方法开始的。整个过程是,创建HttpEngine对象,然后在while循环中进行发送请求,读取响应,获取响应数据,判断响应数据是否重定向,身份验证或请求超时等情况,如果是,再将这些响应数据加入请求数据中重新请求操作,直到得到最终的响应数据,或者请求次数超限。同时,如果路由失败或者发送IO异常等情况时,继续重试。

我们看到了其中捕获了RouteException路由异常,在里面进行了切换路由重试的操作,以及处理了IOException异常,这正是Okhttp支持路由切换,出现连接问题时自动重试的原理了。

接下来我们分析数据的请求过程

发送请求的过程

从上面我们看出,发送请求是在HttpEngine.sendRequest()中进行的。这里先提前总结它的流程,再配合代码分析。

修正填充请求的Request数据

从缓存中获取Request请求对应的响应数据,构建缓存策略CacheStrategy,通过缓存策略计算是使用缓存数据还是继续网络请求。

缓存的处理我们后面再讲

如果使用缓存数据,则直接返回。如果不使用网络请求,且没有缓存数据,则返回不合理请求响应。

如果使用网络请求,则开始获取连接,取得HttpStream流对象。

HttpStream的实现分为Http1xStream和Http2xStream。Http1xStream是针对http 1.1/1.0协议连接的处理http流对象,Http2xStream是针对http 2/SPDY协议连接的处理http流对象

如果请求中存在请求体,且请求方法时Post,put等方法,则使用HttpStream对象开始写入请求头数据,创建请求体输出对,否则就返回,例如get请求,这一步就不做操作。

接下来我们看看读取响应的过程

读取响应的过程

读取响应是在HttpEngine.readResponse()中进行的,这里总结它的流程。

如果userResponse响应数据不为空,表示已经读取过了,直接返回, 如果网络请求和缓存响应为空,表示读取响应之前没有去请求,抛异常。如果网络请求为空,直接返回。接下来执行真正的读取响应操作。

如果是WebSocket,输出请求头数据,然后读取响应数据。

WebSocket协议是基于TCP的一种新的网络协议。它实现了浏览器与服务器全双工(full-duplex)通信——允许服务器主动发送信息给客户端。

如果不是WebSocket,并且不需要写请求体,例如get请求,则交给NetworkInterceptorChain网络拦截链进行处理。

如果不是WebSocket,需要写请求体,则交给httpStream写请求头,然后写请求体,然后读取响应数据。

保存请求头数据到cookies中。

如果存在有效的缓存数据的话,更新该缓存数据。

接下来分析NetworkInterceptorChain是怎么处理网络请求的。我们分析NetworkInterceptorChain的proceed方法。

遍历它链上的所有网络拦截器,对请求和响应进行一层层拦截。

在最里层网络请求中,调用httpStream对象写请求头数据,如果请求体有数据,再写请求体数据,然后readNetworkResponse读取网络响应数据。

接下来我们分析请求头数据的写入过程。

输出请求头

分析Http1xStream的writeRequestHeaders方法,简单说就是将请求行和请求头数据写入到输出流中。

再分析Http2xStream的writeRequestHeaders方法,根据是HTTP2还是SPDY协议得到相应请求头,然后交给FrameConnection(帧连接)去创建一个FrameStream(帧流),然后交给FrameWriter去输出请求头到帧流中。简单介绍下http2和SPDY中流和帧的概念。

http2和SPDY中流和帧的概念

Stream Identifier定义了二进制帧的格式,http2连接上传输的每个帧都关联到一个“流”。流是一个逻辑上的联合,一个独立的,双向的帧序列。这一系列帧在客户端和服务器中通过http2连接进行交换。每个单独的http2连接都可以包含多个并发的流,这些流中交错的包含着来自两端的帧。流既可以被客户端/服务器端单方面的建立和使用,也可以被双方共享,或者被任意一边关闭。在流里面,每一帧发送的顺序非常关键。接收方会按照收到帧的顺序来进行处理。流的多路复用意味着在同一连接中来自各个流的数据包被混合在一起。两个(或者更多)独立的“数据列车”被拼凑到了一辆列车上,最终在终点站被分开。参考 https://www.kancloud.cn/kancloud/http2-explained/49803

接着分析写请求体的过程

输出请求体

分析Http1xStream的writeRequestBody方法,很简单,直接将数据写入到流中。

再分析Http2xStream的writeRequestBody方法,很简单,同样直接将数据写入到流中。

下节,我们分析网络连接的获取,创建,管理,缓存回收等。将会涉及RealConnection、ConnectionPool、StreamAllocation这几个核心的类。

  • 发表于:
  • 原文链接:http://kuaibao.qq.com/s/20180116G0G8IP00?refer=cp_1026

扫码关注云+社区