上一节主要大体看了一下sendRequest的流程,本节来看一下当请求发送出去之后,是如果读取请求体中的数据的,具体的代码都在HttpEngine.readResponse方法中,代码如下:

public void readResponse() throws IOException {if (userResponse != null) {return; // Already ready.}if (networkRequest == null && cacheResponse == null) {throw new IllegalStateException("call sendRequest() first!");}if (networkRequest == null) {return; // No network response to read.}Response networkResponse;if (forWebSocket) {httpStream.writeRequestHeaders(networkRequest);networkResponse = readNetworkResponse();} else if (!callerWritesRequestBody) {networkResponse = new NetworkInterceptorChain(0, networkRequest).proceed(networkRequest);} else {// Emit the request body's buffer so that everything is in requestBodyOut.if (bufferedRequestBody != null && bufferedRequestBody.buffer().size() > 0) {bufferedRequestBody.emit();}// Emit the request headers if we haven't yet. We might have just learned the Content-Length.if (sentRequestMillis == -1) {if (OkHeaders.contentLength(networkRequest) == -1&& requestBodyOut instanceof RetryableSink) {long contentLength = ((RetryableSink) requestBodyOut).contentLength();networkRequest = networkRequest.newBuilder().header("Content-Length", Long.toString(contentLength)).build();}httpStream.writeRequestHeaders(networkRequest);}// Write the request body to the socket.if (requestBodyOut != null) {if (bufferedRequestBody != null) {// This also closes the wrapped requestBodyOut.bufferedRequestBody.close();} else {requestBodyOut.close();}if (requestBodyOut instanceof RetryableSink) {httpStream.writeRequestBody((RetryableSink) requestBodyOut);}}networkResponse = readNetworkResponse();}receiveHeaders(networkResponse.headers());// If we have a cache response too, then we're doing a conditional get.if (cacheResponse != null) {if (validate(cacheResponse, networkResponse)) {userResponse = cacheResponse.newBuilder().request(userRequest).priorResponse(stripBody(priorResponse)).headers(combine(cacheResponse.headers(), networkResponse.headers())).cacheResponse(stripBody(cacheResponse)).networkResponse(stripBody(networkResponse)).build();networkResponse.body().close();releaseStreamAllocation();// Update the cache after combining headers but before stripping the// Content-Encoding header (as performed by initContentStream()).InternalCache responseCache = Internal.instance.internalCache(client);responseCache.trackConditionalCacheHit();responseCache.update(cacheResponse, stripBody(userResponse));userResponse = unzip(userResponse);return;} else {closeQuietly(cacheResponse.body());}}userResponse = networkResponse.newBuilder().request(userRequest).priorResponse(stripBody(priorResponse)).cacheResponse(stripBody(cacheResponse)).networkResponse(stripBody(networkResponse)).build();if (hasBody(userResponse)) {maybeCache();userResponse = unzip(cacheWritingResponse(storeRequest, userResponse));}}

从开始进行分析

此处的userResponse在第一次访问时是null的,因此不会进入此代码块,实际会进入如下判断语句块中

可以看到此处又调用了一个连接拦截器,对请求结果进行拦截,NetworkInterceptorChain也是实现了Intercept.Chain, 具体代码

class NetworkInterceptorChain implements Interceptor.Chain {private final int index;private final Request request;private int calls;NetworkInterceptorChain(int index, Request request) {this.index = index;this.request = request;}@Override public Connection connection() {return streamAllocation.connection();}@Override public Request request() {return request;}@Override public Response proceed(Request request) throws IOException {calls++;if (index > 0) {Interceptor caller = client.networkInterceptors().get(index - 1);Address address = connection().route().address();// Confirm that the interceptor uses the connection we've already prepared.if (!request.url().host().equals(address.url().host())|| request.url().port() != address.url().port()) {throw new IllegalStateException("network interceptor " + caller+ " must retain the same host and port");}// Confirm that this is the interceptor's first call to chain.proceed().if (calls > 1) {throw new IllegalStateException("network interceptor " + caller+ " must call proceed() exactly once");}}if (index < client.networkInterceptors().size()) {// There's another interceptor in the chain. Call that.NetworkInterceptorChain chain = new NetworkInterceptorChain(index + 1, request);Interceptor interceptor = client.networkInterceptors().get(index);Response interceptedResponse = interceptor.intercept(chain);// Confirm that the interceptor made the required call to chain.proceed().if (chain.calls != 1) {throw new IllegalStateException("network interceptor " + interceptor+ " must call proceed() exactly once");}if (interceptedResponse == null) {throw new NullPointerException("network interceptor " + interceptor+ " returned null");}return interceptedResponse;}httpStream.writeRequestHeaders(request);//Update the networkRequest with the possibly updated interceptor request.networkRequest = request;if (permitsRequestBody(request) && request.body() != null) {Sink requestBodyOut = httpStream.createRequestBody(request, request.body().contentLength());BufferedSink bufferedRequestBody = Okio.buffer(requestBodyOut);request.body().writeTo(bufferedRequestBody);bufferedRequestBody.close();}Response response = readNetworkResponse();int code = response.code();if ((code == 204 || code == 205) && response.body().contentLength() > 0) {throw new ProtocolException("HTTP " + code + " had non-zero Content-Length: " + response.body().contentLength());}return response;}}

主要来看下proceed方法

同样还是一个循环递归调用,因此代码其实在最后一层还是会调用一下代码

具体每一行代码的作用在图片中已经做了简单介绍。我们重点来看一下最重要的读取请求结果的方法–readNetworkResponse,代码如下:

到这我们就已经完成了从发送网络请求到读取请求结果的流程,简单总结一下在HttpEngine中两个方法的工作
sendRequest–查找合适的Socket对象并封装在HttpStream中
readResponse–通过HttpStream发送请求,并读取结果封装到Response对象中返回

OkHttp面试之--HttpEngine中的readResponse流程简介相关推荐

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

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

  2. 一文搞懂select语句在MySQL中的执行流程!

    MySQL作为互联网行业使用最多的关系型数据库之一,与其免费.开源的特性是密不可分的.然而,很多小伙伴工作了很多年,只知道使用MySQL进行CRUD操作,这也导致很多小伙伴工作多年后,想跳槽进入大厂, ...

  3. 求职面试时,如何从面试官话语中揣测是否被录用?

    求职面试时,如何从面试官话语中揣测是否被录用? 面试官: 非常感谢您来应聘,我们会尽快联系你,最晚明天下班前给您答复. 基本上可以肯定就是你了,除非遇到特殊情况,HR可能在你没回到家就给你打电话,通知 ...

  4. 团队管理那点事,OKR绩效、核心人才、面试、技术分享、研发流程

    团队管理那点事,OKR绩效.核心人才.面试.技术分享.研发流程 今天来聊聊团队管理,可能你现在还是一线开发,没有带团队,感觉这个话题与你无关,其实不然. 程序员的职业生涯曲折,技术更新迭代快,走技术深 ...

  5. 简历面试择业篇-在面试的过程中你所需要注意的问题

    接着上一篇文章继续,今天主要就在面试的过程中你所需要注意的问题进行分享,希望感兴趣的小伙伴可以坚持看下去同时欢迎提出宝贵的意见让我们一起进步! 11:面试自我介绍应该怎么介绍? (1)首先自报家门介绍 ...

  6. 大厂扩招,如何在大厂面试一击而中?

    /   关于面试你是否出现过这种问题   / 开发4年,卡在初级和高级中间不上不下,出去面试会的基础问题全不问,问的原理问题全不会,背过的题转眼就忘,最后面试被挂惨不忍睹...... 现在的移动开发人 ...

  7. 带你从源码角度分析ViewGroup中事件分发流程

    序言 这篇博文不是对事件分发机制全面的介绍,只是从源码的角度分析ACTION_DOWN.ACTION_MOVE.ACTION_UP事件在ViewGroup中的分发逻辑,了解各个事件在ViewGroup ...

  8. 【Android 异步操作】线程池 ( Worker 简介 | 线程池中的工作流程 runWorker | 从线程池任务队列中获取任务 getTask )

    文章目录 一.线程池中的 Worker ( 工作者 ) 二.线程池中的工作流程 runWorker 三.线程池任务队列中获取任务 getTask 在博客 [Android 异步操作]线程池 ( 线程池 ...

  9. 通过重建Hosting系统理解HTTP请求在ASP.NET Core管道中的处理流程[上]:采用管道处理请求...

    之所以称ASP.NET Core是一个Web开发平台,而不是一个单纯的开发框架,源于它具有一个极具扩展性的请求处理管道,我们可以通过对这个管道的定制来满足各种场景下的HTTP处理需求.ASP. NET ...

最新文章

  1. java8-06-自定义Collector-JoinCollector
  2. 138 条 Vim 命令、操作、快捷键全集
  3. 除夕之夜快乐!自费送10个无人机给大家
  4. Java动态代理的两种实现方法
  5. centos7下python3与python2共存并且开启py3虚拟环境
  6. webstorm主题
  7. 机器学习实战 --- sklearn
  8. 信号的带宽、传输速率、采样率的关系
  9. 淘宝店铺店名起、分类如何定【太原网络营销师】教你
  10. python画实心圆_任意空实心圆形打印|Python练习系列[8]
  11. 关键词搜索排行榜-精准找到行业流量关键词
  12. BIGEMAP如何添加在线第三方地图
  13. AngularJS笔记
  14. 1-11摇号机java_11选5在线模拟摇号
  15. 使用Zerotier实现免费内网穿透
  16. mysql即是主键又是外键怎么写_数据库 既是主键又是外键
  17. 打造超完美主页?20个主页设计技能你不容错过
  18. java信徒齐(七)步走
  19. 第十一章无线渗透 理论篇
  20. 计算机网络第八版--谢希仁 (持续更新中)

热门文章

  1. 不能再让服务这么任性的被访问啦---分布式服务熔断降级限流利器至Hystrix
  2. 883. 三维形体投影面积
  3. 豆豆趣事[2011年12月]
  4. mybaits-plus 代码生成器
  5. 巴比特| 元宇宙每日必读:百度转向海外布局NFT,梦想打造“Web3迪士尼”,胜算几何?...
  6. 关于AI+医疗的调研
  7. ASEMI整流二极管MUR60120PT并联电容有什么用
  8. 软件工程师的核心竞争力是什么-笔记
  9. Java使用JAVE获取MP4播放时长
  10. IOS开发中@2x图片等适应不同分辨率手机