读源码-OkHttp源码解析

本文深入解析OkHttp的源码,重点介绍了拦截器机制,包括RetryAndFollowUpInterceptor、BridgeInterceptor、CacheInterceptor、ConnectInterceptor和CallServerInterceptor的作用和执行流程。通过对这些拦截器的理解,读者可以更好地掌握OkHttp如何处理网络请求和响应,以及其内部的缓存、重试和连接管理策略。
摘要由CSDN通过智能技术生成


本文基于OkHttp版本,该版本是用Kotlin实现:

com.squareup.okhttp3:okhttp:4.7.2

1-基本流程

OkHttp这个框架就不用过多介绍了吧,一句话概括就是对Socket编程的封装实现,方便实现网络通信。什么是Socket编程?Socket是TCP/IP协议的抽象实现,详情可以去看看:一篇文章带你熟悉 TCP/IP 协议-(一)

String testUrl = "https://wanandroid.com/wxarticle/chapters/json";
//@1.初始化OkHttpClient
OkHttpClient client = new OkHttpClient();
//@2.根据url构建Request
final Request request = new Request.Builder().url(testUrl).build();
//@3.发起同步请求
Response syncResponse = client.newCall(request).execute();
//@4.发起异步请求
client.newCall(request).enqueue(new Callback() {
   
    @Override
    public void onFailure(@NotNull Call call, @NotNull IOException e) {
   //TODO 失败回调 }
    @Override
    public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
   //TODO 成功回调}
});

@1.第一步当然是初始化工作了,通过Builder模式构建OkHttpClient。主要是初始化一些基本参数配置,包括任务调度器、连接池、拦截器、线程池等。后面会详细讲述这些内容。核心是任务调度器和拦截器,任务调度器Dispatcher主要是维护了三个任务队列:

  • readyAsyncCalls = ArrayDeque()
    异步方式待执行的任务队列
  • runningAsyncCalls = ArrayDeque()
    异步方式正在执行的任务队列
  • runningSyncCalls = ArrayDeque()
    同步方式执行的任务队列

拦截器机制后面将作为重点讲述。

@2.第二步开始构造请求内容。根据Http协议我们知道发起网络请求的报文协议是请求行+请求头+请求体。这一步就是通过Builder模式将http协议报文的必要信息封装到一个Request对象,后面会将该Request对象转为符合http协议的报文发起一个网络请求。

internal constructor(request: Request) {
   
  this.url = request.url//将字符串url转换成HttpUrl对象,便于提取Url中的scheme、path等信息
  this.method = request.method//请求方法post、get等
  this.body = request.body//请求体,post方法需要将内容放在请求体
  this.tags = if (request.tags.isEmpty()) {
   
    mutableMapOf()
  } else {
   
    request.tags.toMutableMap()
  }
  //请求头,这里是用数组实现,
  //key、value、key、value这样存储键值对,所以肯定是偶数个
  this.headers = request.headers.newBuilder()
}

@3、@4本质上原理是一样的,只是一个是同步实现一个是异步实现,同步异步不做多解释,我们就看看同步请求的实现来了解其原理。client.newCall(request).execute()这里就是通过传入request,创建了一个Call的实现类RealCall的对象,并调用其execute方法执行请求任务,执行完毕返回一个Resonse对象。

override fun execute(): Response {
   
    synchronized(this) {
   
      check(!executed) {
    "Already Executed" }
      executed = true
    }
    timeout.enter()
    callStart()
    try {
   
        //将请求任务添加到dispatcher的runningSyncCalls队列
      client.dispatcher.executed(this)
        //@5.通过拦截器链一步步处理请求任务
      return getResponseWithInterceptorChain()
    } finally {
   
        //任务执行完毕从runningSyncCalls队列移除该任务
      client.dispatcher.finished(this)
    }
}

@5.通过拦截器链一步步处理请求任务。这里就是OkHttp框架的精髓了,将网络请求Request通过一个InterceptorChain加工处理生产出请求结果Response。InterceptorChain就像一条流水生产线,链式调用、分工明确。直接看代码吧:

@Throws(IOException::class)
internal fun getResponseWithInterceptorChain(): Response {
   
    val interceptors = mutableListOf<Interceptor>()
    //(1)用户自定义顶层全局拦截器,优先级最高
    interceptors += client.interceptors
    //(2)错误、重定向拦截器
    interceptors += RetryAndFollowUpInterceptor(client)
    //(3)桥接拦截器,桥接应用层与网络层,添加必要的头信息
    interceptors += BridgeInterceptor(client.cookieJar)
    //(4)缓存处理拦截器
    interceptors += CacheInterceptor(client.cache)
    //(5)连接拦截器。建立C与S的Socket连接
    interceptors += ConnectInterceptor
    //(6)用户自定义的NetworkInterceptor
    if (!forWebSocket) {
   
      interceptors += client.networkInterceptors
    }
    //(7)访问服务端拦截器。
    interceptors += CallServerInterceptor(forWebSocket)
    //通过这些拦截器构造拦截器链RealInterceptorChain
    val chain = RealInterceptorChain(
        call = this,
        interceptors = interceptors,
        index = 0,
        exchange = null,
        request = originalRequest,
        connectTimeoutMillis = client.connectTimeoutMillis,
        readTimeoutMillis = client.readTimeoutMillis,
        writeTimeoutMillis = client.writeTimeoutMillis
    )

    var calledNoMoreExchanges = false
    try {
   
        //通过RealInterceptorChain按顺序执行拦截器,最终得到Response
      val response = chain.proceed(originalRequest)
      if (isCanceled()) {
   
        response.closeQuietly()
        throw IOException("Canceled")
      }
      return response
    } catch (e: IOException) {
   
      calledNoMoreExchanges = true
      throw noMoreExchanges(e) as Throwable
    } finally {
   
      if (!calledNoMoreExchanges) {
   
        noMoreExchanges(null)
      }
    }
}

先大概了解下RealInterceptorChain是如何一步步将Request对象加工成Response对象的,第二章再分析各Interceptor的原理。前面将这些拦截器按顺序添加到了interceptors中,所以RealInterceptorChain.proceed方法就是从index=0开始执行对应拦截器的intercept方法,流程如下(第3章流程总结中有总的流程图):

  • (1)用户自定义的Interceptor(可选)。通过OkHttpClient.Builder().addInterceptor添加,实际应用中会在此流程中往request添加一些全局的业务参数,比如cuid、userId、位置信息等
  • (2)RetryAndFollowUpInterceptor。开启无限循环,执行后续拦截器步骤,根据返回的response
    • 不需要重试或重定向或者不能再重试、重定向,直接返回response跳出循环
    • 重试或重定向,更新request并再次执行后续步骤
  • (3)BridgeInterceptor。
    • 请求前,将Request对象转换为包含http协议信息的请求
    • 执行后续拦截器
    • 请求后,将返回结果Gzip解压出响应体内容
  • (4)CacheInterceptor。
    • 请求前,判断缓存策略,强制缓存则直接返回缓存,不再发起网络请求
    • 执行后续拦截器
    • 请求后,对比缓存策略则使用缓存,否则使用网络返回response,更新缓存
  • (5)ConnectInterceptor
    • 判断当前连接是否可用,不可用则从连接池中获取连接
    • 获取失败则新建连接并执行TCP三次握手建立连接
    • 执行后续流程
  • (6)NetworkInterceptor(可选)。在建立连接后–>正式发送请求前的过程,用户进行一些处理。
  • (7)CallServerIntercepto
    • 请求前,将请求request encode为http协议的报文
    • 请求后,从HTTP响应报文decode出response

2-拦截器

2.1-RetryAndFollowUpInterceptor

经历了用户自定义的Interceptor,第一个拦截器就是RetryAndFollowUpInterceptor,该拦截器主要处理重试和重定向,所以其实现是递归调用RealInterceptorChain.proceed方法执行后续步骤,根据递归结果判断是否需要重试/重定向。来看代码:

@Throws(IOException::class)
override fun intercept(chain: Interceptor.Chain): Response {
   
    。。。//代码省略
    //开启循环
    while (true) {
   
      call.enterNetworkInterceptorExchange(request, newExchangeFinder)
    
      var response: Response
      var closeActiveExchange = true
      try {
   
        if (call.isCanceled()) {
   //请求取消
          throw IOException("Canceled")
        }
        try {
   
            //递归调用,执行后续Interceptor步骤
          response = realChain.proceed(request)
          newExchangeFinder = true
        } 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值