浅谈 okhttp

okhttpSquare公司开源的一个非常便捷的轻量级第三方网络访问框架。它支持同步请求和异步请求。使用起来也是非常的方便。用的人也是越来越多。作为有追求的码农,我们当然要知其怎么用,也要知道它是怎么实现的。那就闲话少说,马上发车。下面就是我自己总结的OkHttp流程图:

未命名文件.jpg

整个OkHttp的请求大致就是上面图片里面的过程,下面我将按照上面的流程图来一步一步解析okhttp的请求过程;

1、OkHttpClient的创建

OkHttpClient的创建我们一般都会选择使用OkHttpClient.Builder,这里我们可以设置一些我们发起请求的一些设置,比如我们自定义的拦截器,缓存啊,超时控制等,可以设置的参数,这里就不具体说了,我们在实际应用的时候自己按需要设置吧。

mOkHttpClient = new OkHttpClient.Builder()
                .callTimeout(10, TimeUnit.SECONDS)
                .connectTimeout(10, TimeUnit.SECONDS)
                .readTimeout(10, TimeUnit.SECONDS)
                .build();

2、调用newCall(Request request)创建RealCall

RealCall是我们真正发起请求的类。它拥有两个比较重要的成员变量clientoriginalRequestclient当然好理解了,就是OkHttpClient的实例了,为什么持有他也很好理解了,既然是实际发起请求的类,客户端手动设置的请求设置当然也要起作用了。originalRequestRequest的实例,我们都知道Http请求包括请求头,请求链接,请求体等等,没错这个类就是包含这些东西的类。Request拥有ulrmethodheadersRequestBody这四个重要的成员变量,ulr代表请求链接,method代表请求方式(get,post等等),headers就是请求头了,RequestBody对应就是请求体了,像post请求就会设置请求体。下面代码表示的就是一个发起post的请求的Request了

private RequestBody createPostRequestBody(Map<String, Object> params) {
        FormBody.Builder bodyBuilder = new FormBody.Builder();
        if (params == null || params.isEmpty())
           return bodyBuilder.build();

        for (Map.Entry<String, Object> entry : params.entrySet()) {
            bodyBuilder.add(entry.getKey(), entry.getValue().toString());
        }

        return bodyBuilder.build();
 }

Request request = new Request.Builder()
                .post(createPostRequestBody(params))
                .url(url)
                .build();

3、发起请求

请求方式有两种,一种是同步请求,一种是异步请求。我们就先讲讲异步请求了。
RealCall的异步请求依赖Dispatcher类来执行。这个类是用来管理异步请求的,它有如下的成员:

    //异步请求最大并发请求数为64
    private int maxRequests = 64;
    //同一主机的异步请求最大并发请求数
    private int maxRequestsPerHost = 5;
    Runnable idleCallback;

    //请求执行的线程池
    private ExecutorService executorService;

    //将要执行的异步请求
    private final Deque<RealCall.AsyncCall> readyAsyncCalls = new ArrayDeque<>();

    //正在执行的异步请求
    private final Deque<RealCall.AsyncCall> runningAsyncCalls = new ArrayDeque<>();

    //正在执行的同步请求
    private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();

它的执行逻辑大概是,先将异步请求放到readyAsyncCalls 等待执行,然后遍历readyAsyncCalls ,如果正在执行的请求数没有达到最大请求数,并且该请求请求的主机也没有到达最大请求书,就会发请求。
通过Dispatcher最终异步请求的执行会转移到AsyncCall的execute方法,接下来就是第四部了。同步请求就比较简单,各位看官们自己去看看源码吧!

4、执行getResponseWithInterceptorChain()

朋友们,终于来到了最核心的地方来了!这个方法里面使用责任链模式来执行拦截器,有点像View的事件传递。拦截器的执行顺序是先执行我们自定义的拦截器,然后是RetryAndFollowUpInterceptorBridgeInterceptorCacheInterceptorConnectInterceptornetworkInterceptorsCallServerInterceptor。这些拦截器是通过RealInterceptorChain一个一个连接起来,按顺序执行。RealInterceptorChain的最核心方法是proceed,这个方法的返回值是Response,这个东西我们就很熟悉嘞。proceed执行大致是:先创建一个新的RealInterceptorChain 对象next,这个next的拦截器下标加1,然后根据下标取出当前拦截器执行interdept方法,interdept方法又会执行next的proceed.。最终执行的轨迹是请求Request被一步步向下包装直到发起请求得到Response,然后Response被一步步向上处理,直到最顶层返回。接下来就是一步步分析拦截器的功能了。

// Call the next interceptor in the chain.
    RealInterceptorChain next = new RealInterceptorChain(interceptors, transmitter, exchange,
        index + 1, request, call, connectTimeout, readTimeout, writeTimeout);
    Interceptor interceptor = interceptors.get(index);
    Response response = interceptor.intercept(next);

5、RetryAndFollowUpInterceptor

这个Interceptor是处理失败重试和重定向处理。大致是经过下面几个检查

  1. 如果连接失败(未发起请求连接失败,请求已发送但连接中断),检查请求是否可以重试,如果可以就发起重试,否则任务请求失败;

  2. 请求成功,但需要判断请求是否需要重定向;判断是否重定向主要依据responseCode来判断以及发起请求的请求体是否支持多次请求。

6、BridgeInterceptor

顾名思义这是一个连接应用层代码和网络代码的桥梁,主要的功能是把我们写的请求代码翻译成http请求能识别的代码,然后把网络返回的Response翻译成我们可以识别的代码。

7、NetworkInterceptors

配置OkHttpClient时设置的 NetworkInterceptors。

8、CacheInterceptor

从名字上我们就知道这和缓存有关。

  1. 首先根据请求读取缓存
  2. 判断缓存是否可用
    1. 使用如果没有缓存,使用请求;
    2. 如果当前请求是https,但是缓存在请求的时候是否经过TLS 握手,如果没有,使用请求(这一块对网络请求不太了解,请大佬补充);
    3. 缓存是否应该被缓存,以及当前请求结果是否应该被缓存,如果不应该,使用网络请求;
    4. 如果请求设置了不使用缓存,或者请求了设置了If-Modified-Since或If-None-Match,使用网络请求;
    5. 检查http请求的缓存使用条件(这一块不是很懂,就不贻笑大方了);
    6. 如果经过上面的判断后,还是需要发起网络请求,并且当前请求设置不使用网络请求,这时候就认为请求失败了,cede是504;
  3. 网络请求成功,再判断是使用网络请求结果还是缓存请求结果,以及更新缓存;

8、ConnectInterceptor

这里主要是建立和服务器的连接通道。这里面涉及到通道的创建和复用,这里及不详细说了(其实我也不太懂,有时间再研究)。

9、CallServerInterceptor

向服务器发起请求。主要是向通道写入请求头,如果有请求体,也写入请求体,然后通过这个通道读取服务器返回的响应。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,837评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,551评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,417评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,448评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,524评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,554评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,569评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,316评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,766评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,077评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,240评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,912评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,560评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,176评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,425评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,114评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,114评论 2 352

推荐阅读更多精彩内容

  • 本来想看看源码提高下自己的水平,以前也有看过某些框架的源码,但是基本都是只看某段,这次打算好好的研究一遍。本来是想...
    键盘上的麒麟臂阅读 499评论 0 1
  • 1.ios高性能编程 (1).内层 最小的内层平均值和峰值(2).耗电量 高效的算法和数据结构(3).初始化时...
    欧辰_OSR阅读 29,358评论 8 265
  • Spring Web MVC Spring Web MVC 是包含在 Spring 框架中的 Web 框架,建立于...
    Hsinwong阅读 22,378评论 1 92
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,647评论 18 139
  • 深与浅的脚印 停在暖与柔的沙滩里 大与小的手掌 编织着你与我的牵绊 我们缓缓而行 把故事写进海的记忆 爷爷,人鱼公...
    小小七阅读 260评论 4 6