透过使用看本质——OkHttp3

本文深入分析OkHttp3的请求流程,包括同步和异步请求,详细解释了RetryAndFollowUpInterceptor、BridgeInterceptor、CacheInterceptor、ConnectInterceptor和CallServerInterceptor等拦截器的作用。通过源码解析,展示了OkHttp如何高效地处理HTTP请求,实现连接复用、GZIP解压、响应缓存等功能。
摘要由CSDN通过智能技术生成

HTTP是现代应用程序网络的方式。这就是我们交换数据和媒体的方式。有效地执行HTTP可以使您的内容加载更快并节省带宽。

OkHttp是一个高效的HTTP库:

  • 支持HTTP / 2,允许对同一主机的所有请求共享一个套接字
  • 通过连接池可减少请求延迟(如果HTTP / 2不可用)
  • 支持GZIP压缩减少数据流量
  • 响应缓存可以完全避免网络重复请求
  • 静默恢复处理常见的连接问题

本文就以请求使用为入口,来深入学习下OkHttp。
在这里插入图片描述

一、请求流程分析

1. 同步请求

Okhttp同步GET请求使用:

// 新建一个Okhttp客户端(也可以通过OkHttpClient.Builder来构造)
OkHttpClient client = new OkHttpClient();
// 构造一个请求对象
Request request = new Request.Builder().url(url).build();
// 执行同步请求,返回响应
Response response = client.newCall(request).execute();
// 从响应体中获取数据
String str = response.body().string();

先来瞧瞧构建OkhttpClient的源码:

open class OkHttpClient internal constructor(
  builder: Builder
) : Cloneable, Call.Factory, WebSocket.Factory {
   
	//若直接实例化OkHttpClient,则调用主构造函数以默认Builder作为参数
	constructor() : this(Builder())

	// 通过builder中的值赋值
	@get:JvmName("dispatcher") val dispatcher: Dispatcher = builder.dispatcher

  	@get:JvmName("connectionPool") val connectionPool: ConnectionPool = builder.connectionPool
	...
	
	class Builder constructor() {
   
	    //分发器
	    internal var dispatcher: Dispatcher = Dispatcher()
	    //连接池
	    internal var connectionPool: ConnectionPool = ConnectionPool()
	    //应用拦截器集合
	    internal val interceptors: MutableList<Interceptor> = mutableListOf()
	    //网络拦截器集合
	    internal val networkInterceptors: MutableList<Interceptor> = mutableListOf()
	    //事件监听工厂
	    internal var eventListenerFactory: EventListener.Factory = EventListener.NONE.asFactory()
	    //连接失败是否重试
	    internal var retryOnConnectionFailure = true
	    internal var authenticator: Authenticator = Authenticator.NONE
	    //是否跟随重定向
	    internal var followRedirects = true
	    internal var followSslRedirects = true
	    //cookie
	    internal var cookieJar: CookieJar = CookieJar.NO_COOKIES
	    //磁盘缓存
	    internal var cache: Cache? = null
	    //dns
	    internal var dns: Dns = Dns.SYSTEM
	    //代理设置
	    internal var proxy: Proxy? = null
	    
		...
    }
    
}

OkhttpClient可以通过构造者配置参数来构建,也可以直接实例化,直接实例化其实也是内部调用构造者,只是传入的是默认builder。

再来看看OkhttpClient的newCall方法

override fun newCall(request: Request): Call = RealCall(this, request, forWebSocket = false)

发现返回的是RealCall,接下来去RealCall中看后续的execute执行方法

override fun execute(): Response {
   
  //确认call没有执行过并置executed为true,否则抛出异常
  check(executed.compareAndSet(false, true)) {
    "Already Executed" }

  timeout.enter()
  callStart()
  try {
   
    //标记执行中
    client.dispatcher.executed(this)
    //通过拦截器链获取网络响应
    return getResponseWithInterceptorChain()
  } finally {
   
    //标记执行结束
    client.dispatcher.finished(this)
  }
}

看起来比较精简,通过拦截器链获取网络响应,然后返回响应(拦截器链路在后续拦截器分析)。

2. 异步请求

Okhttp异步GET请求使用:

OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().url(url).build();
// 执行异步请求,通过回调返回响应
client.newCall(request).enqueue(new Callback() {
   
      @Override
      public void onFailure(@NotNull Call call, @NotNull IOException e) {
   }

      @Override
      public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
   
      	// 从回调中通过响应体获取数据
      	String str = response.body().string();
      }
});

异步请求流程大致和同步请求相似,但是最后的执行方法是enqueue,并传入回调对象。

我们来看看源码:

override fun enqueue(responseCallback: Callback) {
   
  //确认call没有执行过并置executed为true,否则抛出异常
  check(executed.compareAndSet(false, true)) {
    "Already Executed" }
  //监听回调
  callStart()
  //调用Dispatcher的enqueue方法,并传入一个AsyncCall对象
  client.dispatcher.enqueue(AsyncCall(responseCallback))
}

内部调用了客户端的分发器的enqueue方法,并把AsyncCall(responseCallback)作为参数传入,AsyncCall是继承自Runnable,且是RealCall的内部类,我们先看Dispatcher.enqueue()方法

class Dispatcher constructor() {
   
  /** '异步准备执行'队列 */
  private val readyAsyncCalls = ArrayDeque<AsyncCall>()

  /** '异步正在执行'队列,包括取消但至今还没结束的 */
  private val runningAsyncCalls = ArrayDeque<AsyncCall>()

  /** ‘同步正在执行’队列*/
  private val runningSyncCalls = ArrayDeque<RealCall>()
  ...
  internal fun enqueue(call: AsyncCall) {
   
	synchronized(this) {
   
	  //加入准备执行队列
	  readyAsyncCalls.add(call)
	  ...
	}
	// 执行
	promoteAndExecute()
  }

  private fun promoteAndExecute(): Boolean {
   
    this.assertThreadDoesntHoldLock()

    val executableCalls = mutableListOf<AsyncCall>()
    val isRunning
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值