Okhttp

version: 4.9.0

v2-df31eeefb44cc1f36f6a36db5deeb0a5_1440w.jpg

ConnectInterceptor:


v2-d59901ab5502bf4a5615501c977ae1a1_r.jpg
主要类:
  • OkHttpClient:用来根据Request创建Call。每一个OkHttpClient有自己的请求池和线程池。应该公用一个。

  • Request:作为请求信息的封装,内部包含了请求url,请求方法method,请求头headers,请求体RequestBody,tag标签等

  • Response作为相应信息的封装,内部包含对应的请求信息request,http协议protocol,响应码code,响应头headers,响应消息message,响应体ResponseBody等。

  • Call:作为一个请求的接口,提供获取对应请求信息息request,执行请求execute,异步请求入队enqueue,取消请求cancel等方法的定义

  • RealCall:是Call请求的具体实现,实现了同步请求执行,异步请求入队

  • AsynCall:是一个Runnable异步请求任务,分发器Dispatcher负责管理这些异步请求,在可请求数量满足的情况下会交给线程池执行它的execute方法。

  • Dispatcher:是请求Call的分发器,用于管理请求的等待,执行,取消。分为同步请求RealCall和异步请求AsyncCall的管理

  • RealInterceptorChain

  • ConnectionPool

  • RealConnection

  • HttpEngine

  • BridgeInterceptor
    负责把用户构造的请求转换为发送到服务器的请求 、把服务器返回的响应转换为用户友好的响应,是从应用程序代码到网络代码的桥梁
    设置内容长度,内容编码
    设置gzip压缩,并在接收到内容后进行解压。省去了应用层处理数据解压的麻烦
    添加cookie
    设置其他报头,如User-Agent,Host,Keep-alive等。其中Keep-Alive是实现连接复用的必要步骤

  • CacheInterceptor
    通过Request尝试到Cache中拿缓存(里面非常多流程),当然前提是OkHttpClient中配置了缓存,默认是不支持的。

  • ConnectInterceptor
    1.尝试当前连接是否可以复用。
    2.尝试连接池中找可以复用的连接
    3.切换路由,继续在连接中尝试找可以复用的连接
    4.以上都没有则new一个新的。
    5.新的连接放入连接池
    6.建立连接,开始握手

  • RetryAndFollowUpInterceptor
    负责失败自动重连和必要的重定向
    1.协议问题,不能重试。
    2.安全问题,不要重试。
    3.如果是超时问题,并且请求没有被发送,可以重试,其他的就不要重试了。
    4.没有更多的可以使用的路由,不能重试
    5.如果我们在配置OkHttpClient中配置retryOnConnectionFailure属性为false,表明拒绝失败重连,那么这里返回false

  • CallServerInterceptor
    1.先写入请求Header
    2.如果请求头的Expect: 100-continue时,只发送请求头,执行3,不然执行4
    3.根据后台返回的结果判断是否继续请求流程
    4.写入请求体,完成请求
    5.得到响应头,构建初步响应
    6.构建响应体,完成最终响应
    7.返回响应

缓存策略
  • 强制缓存:直接向缓存数据库请求数据,如果找到了对应的缓存数据,并且是有效的,就直接返回缓存数据。如果没有找到或失效了,则向服务器请求数据,返回数据和缓存规则,同时将数据和缓存规则保存到缓存数据库中。
  • 对比缓存:是先向缓存数据库获取缓存数据的标识,然后用该标识去服务器请求该标识对应的数据是否失效,如果没有失效,服务器会返回304未失效响应,则客户端使用该标识对应的缓存。如果失效了,服务器会返回最新的数据和缓存规则,客户端使用返回的最新数据,同时将数据和缓存规则保存到缓存数据库中。
面试
  1. 对于网络请求都有哪些优化
  • 通过ConnectionPool来减少请求延时.可以有5个空闲的connection并保持5分钟。相同IP address公用一个connection。长链接策略
  • 无缝支持GZIP来减少数据流量
  • 以从很多常用的连接问题中自动恢复
    如果你的服务有多个IP地址,当第一个IP请求失败时,OkHttp会交替尝试你配置的其他IP,OkHttp使用现代TLS技术(SNI, ALPN)初始化新的连接,当握手失败时会回退到TLS 1.0。
  • 缓存响应数据来减少重复的网络请求
    OKHttp默认只支持get请求的缓存
    通过字段 Expires 与 Cache-Control 标识
public final class HttpEngine {

  //发送请求
  public void sendRequest() throws RequestException, RouteException, IOException {
    if (cacheStrategy != null) return; // Already sent.
    if (httpStream != null) throw new IllegalStateException();
    //根据用户请求得到实际的网络请求
    Request request = networkRequest(userRequest);
    //这里InternalCache就是对Cache的封装,它的实现在Cache的internalCache中。
    InternalCache responseCache = Internal.instance.internalCache(client);
    //通过Cache的get方法查找缓存响应
    Response cacheCandidate = responseCache != null
        ? responseCache.get(request)
        : null;

    long now = System.currentTimeMillis();
    //构造缓存策略,然后进行策略判断
    cacheStrategy = new CacheStrategy.Factory(now, request, cacheCandidate).get();
    //策略判定后的网络请求和缓存响应
    networkRequest = cacheStrategy.networkRequest;
    cacheResponse = cacheStrategy.cacheResponse;
    
    if (responseCache != null) {
      //使用缓存响应的话,记录一下使用记录
      responseCache.trackResponse(cacheStrategy);
    }

    if (cacheCandidate != null && cacheResponse == null) {
      //使用网络请求,但是之前又有缓存的话,要关闭缓存,释放资源
      closeQuietly(cacheCandidate.body()); // The cache candidate wasn't applicable. Close it.
    }

    // If we're forbidden from using the network and the cache is insufficient, fail.
    if (networkRequest == null && cacheResponse == null) {
      //强制使用缓存,又找不到缓存,就报不合理请求响应了
      userResponse = new Response.Builder()
          .request(userRequest)
          .priorResponse(stripBody(priorResponse))
          .protocol(Protocol.HTTP_1_1)
          .code(504)
          .message("Unsatisfiable Request (only-if-cached)")
          .body(EMPTY_BODY)
          .build();
      return;
    }
    
    //上面情况处理之后,就是使用缓存返回,还是网络请求的情况了

    // If we don't need the network, we're done.
    if (networkRequest == null) {
      //使用缓存返回响应
      userResponse = cacheResponse.newBuilder()
          .request(userRequest)
          .priorResponse(stripBody(priorResponse))
          .cacheResponse(stripBody(cacheResponse))
          .build();
      userResponse = unzip(userResponse);
      return;
    }

    //使用网络请求
    //下面就是网络请求流程了,略
    ...
  }  
}
  1. OkHttp框架中都用到了哪些设计模式
  • Builder模式(OkhttpClient)
  • 责任链模式(拦截器)
  • 简单工厂(CacheStrategy#Factory)
  • 享元模式(Dispatcher的线程池中,不限量的线程池实现了对象复用)
  • 策略模式(在CacheInterceptor中,在响应数据的选择中使用了策略模式,选择缓存数据还是选择网络访问。)
  1. 为什么response.body().string() 只能调用一次
    source().use后调用了close()

  2. addInterceptor与addNetworkInterceptor的区别
    addInterceptor(应用拦截器):
    1,不需要担心中间过程的响应,如重定向和重试.
    2,总是只调用一次,即使HTTP响应是从缓存中获取.
    3,观察应用程序的初衷. 不关心OkHttp注入的头信息如: If-None-Match.
    4,允许短路而不调用 Chain.proceed(),即中止调用.
    5,允许重试,使 Chain.proceed()调用多次.
    addNetworkInterceptor(网络拦截器):
    1,能够操作中间过程的响应,如重定向和重试.
    2,当网络短路而返回缓存响应时不被调用.
    3,只观察在网络上传输的数据.
    4,携带请求来访问连接.

  3. okhttp实现带进度上传下载
    OkHttp把请求和响应分别封装成了RequestBody和ResponseBody,下载进度的实现可以自定义ResponseBody,重写source()方法,上传进度自定义RequestBody,重写writeTo()方法。

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

推荐阅读更多精彩内容