OkHttp 系列八:研究过程中的疑问与解答思路

113 阅读4分钟

OkHttp 研究过程中的疑问与解答思路

本文概述:

  • 本文为OkHttp 系列的最后一篇文章,文章简单总结了个人在研究OkHttp 框架中的简单心得体会;例如:OkHttp 请求的整体流程、分发器是如何工作的、拦截器是如何工作的、应用拦截器与网络拦截器的区别、OkHttp 是如何复用TCP 连接的;

OkHttp 请求的整体流程?

  • 将Request 对象交给OkHttpClient 的newCall 方法,得到RealCall 对象;

  • 在RealCall 对象上执行同步方法

    • 直接调用线程,使用五大拦截器执行任务
  • 在RealCall 对象上执行异步方法

    • 使用分发器,将任务放入线程池中执行,同样使用五大拦截器

分发器是如何工作的?

  • 对于同步请求:

    • 记录同步任务:将RealCall 对象放入正在执行的同步任务队列中,在请求结束后将这个任务从队列移除并回调异步请求队列的finish 方法(OkHttp 4.X 才有这个的)
  • 对于异步请求:

    • 将任务加入ready 队列(等待执行),判断是否需要将ready 中的任务放入running 队列并且启动执行

      • 什么情况下才能做队列任务移动?

        • 同时请求的异步任务数不得大于某一值(默认64)

        • 从ready 中取出的异步任务与其相同的host 不得大于某一值(默认为5 )

          • 若已经存在5 个相同Host 的异步任务在执行,则继续从ready 中检查下一个任务而不是在这里傻等;

拦截器是如何工作的?

  • 整体采用责任链设计模式(将请求者与责任链中的执行者解耦),请求者只需要将任务发给责任链,而不用关心请求过程与细节

  • OkHttp 拦截器有什么?

    • 重试重定向:负责拿到本次请求的结果,判断是否需要重定向;如果请求失败,判断是否需要重试;

    • 桥接:补全请求头,根据响应头判断并执行GZIP 解压、是否保存Cookie;

    • 缓存:如果命中缓存,那么直接将缓存的结果返回上去而不需要再次请求;

    • 连接:获取一个连接,仅此而已

    • 请求服务:拿到之前已经处理好的连接与request,用这个连接将request 发出去

      • 根据HTTP 版本进行Http 报文封装

        • 1.X:文本
        • 2.0:二进制数据
      • 就是用Sokect 的OutputStream 向服务端发送数据,用Socket 的InputStream 接收服务端的回传数据并解析成OkHttp中的Response对象

应用拦截器与网络拦截器的区别?

  • 这两个拦截器都是用户的自定义拦截器

  • 添加顺序区别:应用拦截器会被添加在拦截器首位,而网络拦截器会放在所有拦截器的倒数第二个(请求服务拦截器之前一位 )

  • 数据获取顺序区别:

    • 应用拦截器会第一个拿到请求(用户发起的请求),最后一个接收到响应(经过所有的拦截器处理后的数据 )
    • 网络拦截器会倒数第二个接收到请求(真正发起的请求),第二个接收到响应
  • 执行成功性:

    • 正常情况应用拦截器一定会执行,而网络拦截器则不一定(请求可能通过缓存就拿到了数据 )
  • 应用:

    • 将日志打印拦截器以应用拦截器的方式注册,其打印的请求是用户提交的原始请求而非真实处理后的,而添加到网络拦截器中,这个打印的就是真实发出的请求;

OkHttp 是如何复用TCP 连接的?

  • 在OkHttp 中设计了一个连接池,其中存在一个容器缓存了所有的有效连接对象;

  • 当需要请求时,那么就去连接池中找对应的现成的连接对象(DNS 解析相同、Host 相同,IP 相同、证书要配置得一样、HostName(Host 的验证对象)、SokectXXX、代理、代理选择器HTTP 版本信息相同等) 这样才能完成连接的复用

  • 连接池会清理垃圾连接

    • 什么是垃圾连接:空闲时间超过五分钟
    • 闲置链接数超过五个:LRU 清理空闲连接,直到空闲连接数小于五

总结:

  • OkHttp 实质上是使用Java 完成了对Socket 的封装,帮助实现了HTTP 通信;

\