- 本文章所使用的 OkHttp 源码版本:3.12.10
上一篇:OkHttp 精讲:ConnectInterceptor
源码解析
在这里我们看到,拦截器使用了一个 Http 编解码器来写出请求头
那么问题来了,为什么要用编解码器来写出,我直接把所有的数据都拼接出来然后发送给后台不行么?
- 这个是请求报文示例
这个是响应报文示例
这个问题其实我们之前也讲过,Http 协议分为两种,请求报文和响应报文,请求报文里面有请求头、Body,而响应报文里面有响应头、Body、响应码,但是实际不止这些,还有请求方式(Get 还是 Post)、协议类型(Http 还是 Https)、协议版本(Http 1.0 还是 Http 2.0),我们如果使用最原始的方式,将这些信息统一转换成纯文本再传给后台,那么会有一个问题,我们将无法管控这些信息,因此 OkHttp 在请求的过程中将这些信息包装成了对象,而在传输的时候将这些对象转换成纯文本给后台,而响应的时候也雷同。所以 Http 编解码器就成为了负责对象和文本之间相互转换的工具。
- 会判断当前请求方式是否支持写入 Body,在这里我们可以看到,Get 和 Head 请求是不能有 Body 的,所以就算你在 Get 或 Head 请求上面指定了 Body,OkHttp 也不会帮你传过去。
- 在写出请求头之后,接下来就是写出请求的 Body
- 到这里,请求报文的写出工作已经结束了,接下来就是处理响应报文了
- 跟我们刚刚讲过的处理请求报文的方式差不多,先处理 Header 再处理 Body
再把请求发送的时间和请求响应的时间设置给 Response 对象
有了这两个时间,我们可以直接通过计算来得出请求耗时
在这里我们分享一个题外话,看源码的好处到底究竟在哪里
- 在没看源码之前,我的请求耗时是这样写的
在看完源码之后,我的请求耗时是这样写的
虽然两者都差不多,但是第一种存在一定的偏差,从严格的角度来分析,第二种写法完胜第一种,这个就是看源码的好处。
讲完了这个题外话,让我们回归主题继续往下讲
我们可以看到,当响应码为 100 时,这个时候拦截器又读取了一次响应
那么接下来让我们回顾一下之前看过的HTTP状态码对照表
状态码 | 含义 |
---|---|
100 | 客户端应当继续发送请求。这个临时响应是用来通知客户端它的部分请求已经被服务器接收,且仍未被拒绝。客户端应当继续发送请求的剩余部分,或者如果请求已经完成,忽略这个响应。服务器必须在请求完成后向客户端发送一个最终响应。 |
原来这块属于 Http 协议的内容,当后台返回的响应码是 100 的时候,我们应当遵守协议的规则,再发起一次网络请求来重新获取响应的内容
当然这块 OkHttp 已经帮我们处理了,所以我们不需要自己再去处理了
读完响应头部分,接着就是把后台返回的 Body 部分通过 Http 编解码器读取并转换成 Java 对象
等下,你是不是讲漏了上面的判断,响应码是 101 会怎么样?
让我们看看上面这两个判断是什么意思
- 用于 WebSocket?那么问题来了,什么是 WebSocket?让我们来一波扫盲
- WebSocket 和 Http 属于 TCP 协议,都是应用层协议,WeSocket 的出现是为了解决 Http 只能单向通讯的问题,也就是只能客户端请求服务器的问题,而 WebSocket 可以建立双向通讯,也就是客户端和服务器可以相互访问,常被用于解决使用 Http 不断轮询来获取最新数据的问题。
状态码 | 含义 |
---|---|
101 | 服务器已经理解了客户端的请求,并将通过Upgrade 消息头通知客户端采用不同的协议来完成这个请求。在发送完这个响应最后的空行后,服务器将会切换到在Upgrade 消息头中定义的那些协议。 只有在切换新的协议更有好处的时候才应该采取类似措施。例如,切换到新的HTTP 版本比旧版本更有优势,或者切换到一个实时且同步的协议以传送利用此类特性的资源。 |
而响应码 101 则表示要切换协议,具体是什么协议服务器会在响应头中指定
而 WebSocket 需要借助一次 Http 请求来完成 TCP 握手,所以响应码 101 则表示服务器告诉客户端,请求要从 Http 协议切换成 WebSocket 协议
既然这个只是 WebSocket 握手阶段,那么 Body 是空的自然也可以理解
那么问题来了,OkHttp 到底支不支持 WebSocket 呢?
OkHttp 是支持 WebSocket 的,不得不感叹:看源码长知识
关于 WebSocket 的知识我们不再多讲,让我们接着回去讲剩下的内容
名称 | 说明 | 示例 |
---|---|---|
Connection | 表示是否需要持久连接。(HTTP 1.1默认进行持久连接) | Connection: close |
- 至于什么是 Http 长连接我们在上一篇文章已经讲过了,这里不再多讲
状态码 | 含义 |
---|---|
204 | 服务器成功处理了请求,但不需要返回任何实体内容,并且希望返回更新了的元信息。响应可能通过实体头部的形式,返回新的或更新后的元信息。如果存在这些头部信息,则应当与所请求的变量相呼应。 如果客户端是浏览器的话,那么用户浏览器应保留发送了该请求的页面,而不产生任何文档视图上的变化,即使按照规范新的或更新后的元信息应当被应用到用户浏览器活动视图中的文档。 由于204响应被禁止包含任何消息体,因此它始终以消息头后的第一个空行结尾。 |
205 | 服务器成功处理了请求,且没有返回任何内容。但是与204响应不同,返回此状态码的响应要求请求者重置文档视图。该响应主要是被用于接受用户输入后,立即重置表单,以便用户能够轻松地开始另一次输入。 与204响应一样,该响应也被禁止包含任何消息体,且以消息头后的第一个空行结束。 |
- Http 协议规定响应码 204 或 205 都是不能有 Body 的,如果 Body 有内容证明违背了 Http 协议,则直接抛出异常
源码总结
- 这个拦截器的作用其实很简单,就是将 Request 对象中的请求头和请求的 Body 写出给后台,再将后台返回的响应头和响应的 Body 写入到 Response 对象中,这个写出写入过程都由一个 Http 编解码器来完成。通过这个拦截器,我们还知道了 OkHttp 是支持 WebSocket 的,只不过 WebSocket 需要借助一次 Http 请求来完成 TCP 握手,这个过程称之为协议升级。