Okhttp学习总结

okhttp源码
如何下载查看源码
OkHttp使用完全教程
okhttp 源码浅析
OKHttp源码解析(九):OKHTTP连接中三个"核心"RealConnection、ConnectionPool、StreamAllocation
okhttp连接池复用机制
关于OkHttp3中publicsuffixes.gz的使用
根据Interceptor 分析 OkHttp
OkHttp 之 网络请求耗时统计
Kalle是一个Android平台的HttpClient
分块编码(Transfer-Encoding: chunked)
Android Https相关完全解析 当OkHttp遇到Https
Okhttp之RealConnection建立链接简单分析
OKHttp源码解析(三)——分发器Dispatcher
OkHttp3.0解析(三)——谈谈内部任务分发器dispatcher
OKHttp源码解析(1)----整体流程
Android高工:okhttp原理详解,搞懂了直接去虐面试官~
面试官:听说你熟悉OkHttp原理?

一、优势
支持HTTP/2,HTTP/2通过使用多路复用技术,在一个单独的TCP链接上支持并发,通过在一个连接上一次性发送多个请求来发送或接收数据
如果HTTP/2不可用,链接池减少请求延迟
支持GZIP,额可以压缩下载体积
响应缓存可以避免重复请求网络
会从很多常用的连接问题中自动恢复,如果您的服务器配置了多个IP地址,当第一个IP连接失败的时候,OKHttp会尝试下一个IP地址
OKHttp还处理了代理服务器问题和SSL握手失败问题

流程图
在这里插入图片描述

二、拦截器
Interceptor可以说是OkHttp的核心功能,它就是通过Interceptor来完成监控管理、重写和重试请求的。OkHttp使用lists来管理Interceptors,让这些Interceptors按顺序被调用。

Application Interceptors和Network Interceptors分别位于七层模型的第一层和第六层。这个从RealCall里的getResponseWithInterceptorChain方法中就可以看出来:

//RealCall.java
Response getResponseWithInterceptorChain() throws IOException {
    //新建一个List用来保存拦截器
    List<Interceptor> interceptors = new ArrayList<>();
    //添加我们自定义的应用拦截器
    interceptors.addAll(client.interceptors());
    //添加负责重试重定向的拦截器
    interceptors.add(new RetryAndFollowUpInterceptor(client));
    //添加负责转换请求响应的拦截器
    interceptors.add(new BridgeInterceptor(client.cookieJar()));
    //添加负责缓存的拦截器
    interceptors.add(new CacheInterceptor(client.internalCache()));
    //添加负责管理连接的拦截器
    interceptors.add(new ConnectInterceptor(client));
    if (!forWebSocket) {//没有特殊要求,不使用WebSocket协议,WebSocket是什么?自行百度
      //添加我们自定义的网络拦截器
      interceptors.addAll(client.networkInterceptors());
    }
    //添加负责发起请求获取响应的拦截器
    interceptors.add(new CallServerInterceptor(forWebSocket));

    //构造第一个Chain
    Interceptor.Chain chain = new RealInterceptorChain(interceptors, transmitter, null, 0,
        originalRequest, this, client.connectTimeoutMillis(),
        client.readTimeoutMillis(), client.writeTimeoutMillis());

    boolean calledNoMoreExchanges = false;
    try {
       //调用Chain的proceed(Request)方法处理请求
      Response response = chain.proceed(originalRequest);
      //...
      //返回响应
      return response;
    }
    //...省略异常处理
  }

getResponseWithInterceptorChain()干了三件事:1、添加拦截器到interceptors列表中;2、构造第一个Chain(Chain是Interceptor的一个内部接口,它的实现类是RealInterceptorChain);3、调用Chain的proceed(Request)方法处理请求。
在这里插入图片描述

三、各拦截器详解:okhttp3源码分析之拦截器
1、添加拦截器到interceptors列表中
除了添加我们自定义的拦截器外,还添加了默认的拦截器,如下:

(1)RetryAndFollowUpInterceptor:
负责失败重试和重定向。
(2)BridgeInterceptor:
负责把用户构造的Request转换为发送给服务器的Request和把服务器返回的Response转换为对用户友好的Response。(例如,对于Request,当开发者没有添加Accept-Encoding时,它会自动添加Accept-Encoding : gzip,表示客户端支持使用gzip;对于Response,当Content-Encoding是gzip方式并且客户端是自动添加gzip支持时,它会移除Content-Encoding、Content-Length,然后重新解压缩响应的内容。)
(3)CacheInterceptor:
负责读取缓存以及更新缓存。(okhttp的缓存机制 = Cache缓存实现(DiskLruCache) + 基于HTTP的缓存策略)

  • HTTP的缓存策略:(1、Expires 策略;2、Last-Modified/If-Modified-Since 要配合 Cache-Control 使用;3、Etag/If-None-Match 也要配合 Cache-Control 使用)
    • 种类
      • Expires 策略 :Expires 是 Web 服务器响应消息头字段,在响应 http 请求时告诉浏览器在过期时间前浏览器可以直接从浏览器缓存取数据,而无需再次请求。不过 Expires 是 HTTP 1.0 的东西,现在默认浏览器均默认使用 HTTP 1.1,所以它的作用基本忽略。Expires 的一个缺点就是,返回的到期时间是服务器端的时间,这样存在一个问题,如果客户端的时间与服务器的时间相差很大(比如时钟不同步,或者跨时区),那么误差就很大,所以在 HTTP 1.1 版开始,使用 Cache-Control: max-age = 秒替代。
      • Cache-control 策略(重点关注): Cache-Control 与 Expires 的作用一致,都是指明当前资源的有效期,控制浏览器是否直接从浏览器缓存取数据还是重新发请求到服务器取数据。只不过 Cache-Control 的选择更多,设置更细致,如果同时设置的话,其优先级高于 Expires。值可以是public、private、no-cache、no- store、no-transform、must-revalidate、proxy-revalidate、max-age。各个消息中的指令含义如下:
      •  Public指示响应可被任何缓存区缓存。
        
      •  Private指示对于单个用户的整个或部分响应消息,不能被共享缓存处理。这允许服务器仅仅描述当用户的部分响应消息,此响应消息对于其他用户的请求无效。
        
      •  no-cache指示请求或响应消息不能缓存,该选项并不是说可以设置”不缓存“,容易望文生义~
        
      •   no-store用于防止重要的信息被无意的发布。在请求消息中发送将使得请求和响应消息都不使用缓存,完全不存下來。
        
      •   max-age:指示客户机可以接收生存期不大于指定时间(以秒为单位)的响应。
        
      •   min-fresh指示客户机可以接收响应时间小于当前时间加上指定时间的响应。
        
      •   max-stale指示客户机可以接收超出超时期间的响应消息。如果指定max-stale消息的值,那么客户机可以接收超出超时期指定值之内的响应消息。)
        
      • Last-Modified/If-Modified-Since: Last-Modified/If-Modified-Since 要配合 Cache-Control 使用。
      • Etag/If-None-Match: Etag/If-None-Match 也要配合 Cache-Control 使用。
    • 问题 : Last-Modified 已经足以让浏览器知道本地的缓存副本是否足够新,为什么还需要 Etag(实体标识)呢?原因如下:
      • 1、Last-Modified的限制: (1)Last-Modified标注的最后修改只能精确到秒级,如果某些文件在1秒钟以内,被修改多次的话,它将不能准 确标注文件的修改时间如果某些文件会被定期生成,当有时内容并没有任何变化,但Last-Modified却改变了,导致文件没法使用缓存有可能存在服务器没有准确获取文件修改时间,或者与代理服务器时间不一致等情形 。(2)资源修改时间并不能作为资源是否修改的唯一依据,比如资源文件是Daily Build的,每天都会生成新的,但是其实际内容可能并未改变
      • 2、Etag的作用: Etag 是服务器自动生成或者由开发者生成的对应资源在服务器端的唯一标识符,能够更加准确的控制缓存。Last-Modified 与 ETag 一起使用时,服务器会优先验证 ETag。

浏览器 HTTP 协议缓存机制详解
Android DiskLruCache完全解析,硬盘缓存的最佳方案

在这里插入图片描述
(4)ConnectInterceptor:
负责与服务器建立连接并管理连接。
(5)CallServerInterceptor:
负责向服务器发送请求和从服务器读取响应。

四、连接池原理
由于HTTP是基于TCP,TCP连接时需要经过三次握手,为了加快网络访问速度,我们可以Reuqst的header中将Connection设置为keepalive来复用连接。

Okhttp支持5个并发KeepAlive,默认链路生命为5分钟(链路空闲后,保持存活的时间),连接池有ConectionPool实现,对连接进行回收和管理。

1、连接池的清理
在这里插入图片描述
ConectionPool在内部使用一个异步线程来清理连接。

当连接池中有连接时:清理任务由cleanup()方法完成,首先执行清理,并返回下次需要清理的间隔时间,调用调用wait() 方法释放锁。等时间到了以后,再次进行清理,并返回下一次需要清理的时间间隔,再次进入wait,以此循环往复。

当连接池中没有连接时:cleanup()返回-1,跳出循环,下次有连接加进来时,再次开启线程进行循环清理。

之所以连接池线程可以跳出循环,是因为,他是子线程,而looper选择一直阻塞是因为他是主线程,如果跳出,程序执行结束。
在这里插入图片描述
首先统计空闲连接数量;

1、然后通过for循环查找最长空闲时间的连接以及对应空闲时长;
2、然后判断这个最长空闲时间的连接是否超出最大空闲连接数或者或者超过最大空闲时间,满足其一则清除最长空闲的连接。如果不满足清理条件,则返回一个对应等待时间。
这个对应等待的时间又分二种情况:

1、有空闲连接:则返回:keepAliveDurationNs-longestIdleDurationNs;
2、没有空闲的连接,则返回:keepAliveDurationNs
注意: 清除一个空闲连接后,会返回0,再次立即开始清理。

如何统计空闲连接呢?
在这里插入图片描述
StreamAllocation创建或者复用一个Connection后,会将自己添加到Connection的connection.allocations列表中,数据读取完毕之后,会将自己从Connection的connection.allocations中移除,所以判读一个Connection是否是空闲连接可以采用引用计数法,判断connection.allocations列表中是否有StreamAllocation,如果没有就是空闲连接,否则不是。

五、OkHttp中的设计模式
1、责任链模式:拦截器链
2、单例模式:线程池
2、观察者模式:各种回调监听

策略模式:缓存策略

Builder模式:OkHttpClient的构建过程

外观模式:OkHttpClient封装了很多类对象

工厂模式:Socket的生产

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值