Okhttp

基础用法

okhttp的用法很简单,先创建一个OkHttpClient构造方法创建一个OkHttpClient对象,然后再通过Request的Builder方法创建一个Request对象,然后就调用client的newCall方法传入request对象,创建一个Call,就可以通过这个Call来进行同步或者异步网络请求了。
在这里插入图片描述

通过Http进行WebScoket请求

首先是创建OkHttp的Client,只不过创建Client的时候需要配置下读的超时时间、写的超时时间以及连接的超时时间。在正常的构建Request,以及一个WebsocketListener回调。然后调用okHttp的newWebSocket方法传入request和websocketListener,之后调用okHttpClient.dispatcher.executorService.shutdown去执行。

其中我们在WebSocketListener回调中需要设置下面几个方法:

  • onOpen:建立连接时调用,在此方法中发送消息
  • onMessage:收到消息时调用此方法
  • onClosed:链接关闭成功时调用
  • onClosing:连接正在关闭时调用
  • onFailure:期间出错时调用

为什么只用一个OkHttpClient

OkHttpClient是okhttp框架的客户端,用户使用okhttp进行各种设置,发起各种网络请求都是通过OkHttpClient完成的。每个OkHttpClient内部都维护了属于自己的任务队列,连接池,Cache,拦截器等,所以应该全局共享一个OkHttpClient实例,是应该不重复创建连接池和线程池。而且单例不会影响OkHttpClient的拓展性,,在需要特殊配置一个OKHttpClient的时候,这个局部的OKHttpClient 引用的连接池和线程池是复用自全局单例的就行(使用Client.newBuilder再配置局部属性)

拦截器

流程

经过Dispatcher调度器的调度后,请求就会进入OkHttp的拦截器链中。拦截器链是典型的责任链设计模式。

然后拦截器的调度主要是通过RealInterceptorChain来操作的。

RetryAndFollowUpIntercrptor:重定向拦截器

进入拦截器链后,首先是RetryAndFollowUpInterceptor重定向拦截器。他的主要作用是负责请求的重定向操作,用于处理网络请求失败后的重试。

当发生重定向事件的时候,首先要销毁与原url建立的链接,与新的地址进行一个链接,创建对应的StreamAllocation。

这里的重定向是指client向server发送一个请求,要求获取一个资源,server接收到这个请求后,发现请求的这个资源实际存放在另一个位置,于是server在返回的response header的Location字段中写入那个请求资源的正确的URL,并设置reponse的状态码为30x,client接收到这个response后,发现状态码为重定向的状态码,就会去解析到新的URL,根据新的URL重新发起请求。

重试就是指,如果在请求的过程中,发生了Route异常或者IO异常,那么就会经过死循环进行重试,如果不是这个问题,就不会重试

BridgeInterceptor:桥拦截器

之后会进入BridgeInterceptor桥拦截器,在这块会把传入的请求添加请求头,并根据需求判断是否需要添加Cookies。当有响应之后,会为响应添加对应的响应头,并保存cookies,同时在这一层会判断是否需要gzip压缩。

CacheInterceptor:缓存拦截器

如果在BridgeInterceptor正常,那就会进入下一个拦截器:CacheInterceptor缓存拦截器。在这块主要是缓存。他首先通过将请求的url进行了md5加密后的转为了16进制的字符串作为key,根据这个key,去磁盘中获得这个缓存(OKio还有DiskLruCache获得,LRU算法),当获得缓存后紧接着获得缓存策略,根据缓存中请求头的Cache_Control字段,以及缓存存在的时长,判断缓存是否可用,如果可用,就不去进行网络请求,直接将缓存的Response返回。如果不可以就会继续进行网络请求,还是会下一次的拦截器。然后将的Response进行跟据需要缓存更新,或者存入。这里的存入和取的时候一样,使用url获得的md5值来将Response存入到磁盘中。同时缓存只存入get方法。

ConnectInterceptor:连接拦截器

在之后进入连接拦截器,他会首先获得一个健康的连接,健康的连接是用过下面的过程来获得的:当本地有连接时,直接用,如果没有去连接池查找,找到后,直接用,否则补充一些路由信息后,再次查找。如果还是没有找到,此时他就会去创建一个新的连接。当创建新连接时,它就会建立一个socket连接,并用OKio封装输入输出流。而连接池的是ConnectionPool通过双端队列进行维护。默认的最大空闲连接数为5,在清理回收的时候利用(连接上transmitter可用数量)引用计数法以表明此连接是否是空闲连接。

CallServerInterceptor:请求拦截器

连接拦截器之后就是请求拦截器,这块是真正进行请求的。他会把连接中封装好的Okio,先将请求头写入到连接中,然后会进行100-continue判定,来看服务器是否处理POST请求,如果可以接受或者无100-continue判定,那么他就会继续将请求发送过去。之后就是接受服务器返回的响应头和响应体。

最后就是将结果依次有拦截器链返回,最后将Response返回到要调用OkHttp的地方。


应用拦截器和网络拦截器区别

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wx5qV8yQ-1615630224114)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/0d579132-606c-4d2f-bb06-7aa58f363c2d/Untitled.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AUykgaZw-1615630224116)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/a3d1fe07-26b5-4e18-95e4-746ced30c8b4/Untitled.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uyxPjJpB-1615630224119)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/34dbc740-816e-418d-969e-535bbb9493e5/Untitled.png)]

Application interceptors

  • 不需要关心是否重定向或者失败重连
  • 应用拦截器只会调用一次,即使数据来源于缓存
  • 只考虑应用的初始意图,不去考虑Okhhtp注入的Header比如:if-None-Match,意思就是不管其他外在因素只考虑最终的返回结果
  • 根据第三张图我们可以看出,自定义的应用拦截器是第一个开始执行的拦截器,所以这句话的意思就是,应用拦截器可以决定是否执行其他的拦截器,通过Chain.proceed().
  • 和上一句的意思差不多,可以执行多次调用其他拦截器,通过Chain.proceed().

Network Interceptors

  • 根据第二张图,我们可以理解这句话的意思是,网络拦截器可以操作重定向和失败重连的返回值
  • 根据第一张图,我们可以以看出,这句换的意思是,取缓存中的数据就不会去还行Chain.proceed().所以就不能执行网络拦截器
  • 意思是通过网络拦截器可以观察到所有通过网络传输的数据
  • 根据第三张图我们可以看出,请求服务连接的拦截器先于网络拦截器执行,所以在进行网络拦截器执行时,就可以看到Request中服务器请求连接信息,因为应用拦截器是获取不到对应的连接信息的。
    -在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

请求流程

在构造OkHttp请求流程中,核心就在那个newCall方法,newCall方法的作用就是根据传入的request创建了一个call。而这块newCall其实是Call接口唯一的实现类RealCall实现的。newCall就调用了RealCall的newRealCall方法。

所以也就是说我们的同步异步方法都是RealCall在处理。而调用RealCall的同步或者异步请求方法最后都会进入dispatcher方法进行调度。

Dispatcher维护了三个队列,分别是准备运行的异步队列、正在运行的异步队列以及正在运行的同步队列。

如果是同步请求就直接加入正在运行的同步队列中,直接调用getResponseWithInterceptorChain()。

如果是异步请求,先放到就绪队列中去,然后再判断是否达到同时最大请求数64或者同一host最大请求数5,如果满足其中一个条件时,就把请求放入正在等待的异步队列,否则放入正在运行的异步队列。每当一个请求完成后,就通过try catch执行finish方法,在这个方法中就把ReadyAsyncCalls中满足条件的请求放入RunningAsyncCalls。然后再通过线程池去执行getResponseWithInterceptorChain()。

OkHttp缓存

再详细说说CacheInterceptor的流程:

  1. 如果此次网络请求有缓存数据,则通过请求的URL从DiskLruCache中获取响应缓存,并根据请求中的Cache-Control字段来获取缓存策略。
  2. 如果根据缓存策略不使用网络请求(例如Cache-Control的值为only-if-cached,仅用缓存 ),并且没有缓存,返回504错误。
  3. 根据缓存策略不使用网络请求,则直接使用缓存。
  4. (走到这,说明网络请求可用。)进入ConnectInterceptor进行网络请求。如果响应码是304 Not Modified,则缓存可用(对比缓存),更新缓存后直接返回。
  5. 否则读取返回的结果并进行缓存。

用到的设计模式

  • 建造者模式
    这从它的基本使用就可以看出来:
    在这里插入图片描述
  • 工厂模式
    一个是OkHttpClient类实现的WebSocket.Factory接口,还有一个就是Call接口。
public interface Call extends Cloneable {
  ...
  interface Factory {  
    Call newCall(Request request);
  }
}
  • **责任链模式

优点**
1)降低耦合度:客户端不需要知道请求由哪个处理者处理,而处理者也不需要知道处理者之间的传递关系,由系统灵活的组织和分配。
2)良好的扩展性:增加处理者的实现很简单,只需重写处理请求业务逻辑的方法。

缺点
1)请求会从链头发出,直到有处理者响应,在责任链比较长的时候会影响系统性能
2)请求递归,调试排错比较麻烦

  • 观察者模式
    观察者有两个,一个是EventListener,另一个是WebSocketListener。两者都可以看作是生命周期监听器,前者监听请求/响应,后者监听web socket。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值