2022-03-06

框架

okhttp

  OkHttpClient okHttpClient =  new OkHttpClient.Builder()
               .cache(new Cache(getCacheDir(),1000))
               .addInterceptor() // 应用拦截器,放在最前面
               
               .addNetworkInterceptor() //网络拦截器,倒数第二个,在callserver 之前
               .dns() //设置httpdns
               .proxy() //设置代理
               .build();


okHttpClient.newCall(request) 返回realcall
同步 execute


  override fun execute(): Response {
    //1,查看是否已经执行过,原子类,期望是false,是的话改为true
    check(executed.compareAndSet(false, true)) { "Already Executed" }

    timeout.enter()
    callStart()
    try {
//2,进入分发器,加入同步队列,总共有3个队列,同步,异步进行,异步准备
      client.dispatcher.executed(this)
  //3,通过拦截器进行请求
      return getResponseWithInterceptorChain()
    } finally {
//4,执行完毕,
      client.dispatcher.finished(this)
    }
  }
//dispatcher 需要注意,新版本分发器,finish方法都会走promoteAndExecute()
//执行异步请求获取判断
 private fun  finished(calls: Deque, call: T) {
    val isRunning = promoteAndExecute() //这个异步队列里 获取请求进行执行的方法
  }

异步

override fun enqueue(responseCallback: Callback) {
  //1,检查call有没有被用
    check(executed.compareAndSet(false, true)) { "Already Executed" }

    callStart()
//2 ,进行分发,注意这边给的是AsyncCall,同步直接给分发realcall
    client.dispatcher.enqueue(AsyncCall(responseCallback))
  }

//Dispatcher
internal fun enqueue(call: AsyncCall) {
    synchronized(this) {
//1,加入准备队列
      readyAsyncCalls.add(call)

      // Mutate the AsyncCall so that it shares the AtomicInteger of an existing running call to
      // the same host.
//2,判断如果不是websocket请求
      if (!call.call.forWebSocket) {
      //2.1 找到是否存在这个host的请求
        val existingCall = findExistingCallWithHost(call.host)
    //2.2存在的话 callsPerHost 指向 同样host的callsPerHost 值
        if (existingCall != null) call.reuseCallsPerHostFrom(existingCall)
      }
    }
//3 开始从异步准备队列获取
    promoteAndExecute()
  }

//3 

private fun promoteAndExecute(): Boolean {
 
    synchronized(this) {
      val i = readyAsyncCalls.iterator()
      while (i.hasNext()) {
        val asyncCall = i.next()
      //1,判断,请求数 有没有超过64个,有就结束
        if (runningAsyncCalls.size >= this.maxRequests) break // Max capacity.
// 2,判读啊这个host的请求 有没有超过5,有超过,就拿下一个
        if (asyncCall.callsPerHost.get() >= this.maxRequestsPerHost) continue // Host max capacity.
    //3,请求队列移除
        i.remove()
//5,callsPerHost + 1 这个主要用来判断同个host请求超过5没
        asyncCall.callsPerHost.incrementAndGet()
// 这个是干嘛呢,比如我前面一个请求没有,那我一次可以添加到第64个
        executableCalls.add(asyncCall)
// 6,加入云队列
        runningAsyncCalls.add(asyncCall)
      }
      isRunning = runningCallsCount() > 0
    }

    for (i in 0 until executableCalls.size) {
      val asyncCall = executableCalls[i]
      //并行执行这些请求,
      //executorService = ThreadPoolExecutor(0, Int.MAX_VALUE, 60, TimeUnit.SECONDS,
            SynchronousQueue(), threadFactory("$okHttpName Dispatcher", false))
    //差不多就是 Cachepool
      asyncCall.executeOn(executorService)
    }

    return isRunning
  }


fun executeOn(executorService: ExecutorService) {
      var success = false
      try {
        executorService.execute(this)
        success = true
      } catch (e: RejectedExecutionException) {

      } finally {
      //其实是成功失败 都会调用finished 方法,那么为什么这边只有!success呢
      //因为run里已经执行了
        if (!success) {
       
          client.dispatcher.finished(this) // This call is no longer running!
        }
      }
    }

 override fun run() {
      
 
        try {
        //通过拦截器进行请求
          val response = getResponseWithInterceptorChain()
          signalledCallback = true
          responseCallback.onResponse(this@RealCall, response)
        } catch (e: IOException) {
         
        } finally {
        //调用分发器的finish方法
          client.dispatcher.finished(this)
        }
      }
    }
  }

 internal fun finished(call: AsyncCall) {
      //这边和直接realcall不同,她会先加吧callsPerHost -1
    call.callsPerHost.decrementAndGet()
    finished(runningAsyncCalls, call)
  }

RetryAndFollowUpInterceptor 重定重试向拦截器

1,会根据请求返回结果,判断是否重试重定向

override fun intercept(chain: Interceptor.Chain): Response {
    //循环,方便失败以后重试请求
    while (true) {

      var response: Response

      try {
        //1,用户主动取消的,不进行重试重定向
        if (call.isCanceled()) {
          throw IOException("Canceled")
        }

        try {
          //执行到下一个拦截器
          response = realChain.proceed(request)
        } catch (e: RouteException) {
          //出错了 recover 方法判断要不要进行重新请求
          if (!recover(e.lastConnectException, call, request, requestSendStarted = false)) {
            throw e.firstConnectException.withSuppressed(recoveredFailures)
          } else {
            recoveredFailures += e.firstConnectException
          }
          newExchangeFinder = false
          continue
        } catch (e: IOException) {
          // An attempt to communicate with a server failed. The request may have been sent.
          if (!recover(e, call, request, requestSendStarted = e !is ConnectionShutdownException)) {
            throw e.withSuppressed(recoveredFailures)
          } else {
            recoveredFailures += e
          }
          newExchangeFinder = false
          continue
        }
      // 判断不需要重试以后,看看是不是需要重定向
        // Attach the prior response if it exists. Such responses never have a body.
     
      //进行重定向请求
        val followUp = followUpRequest(response, exchange)

        

        //不会重试重定向
        if (followUpBody != null && followUpBody.isOneShot()) {
          closeActiveExchange = false
          return response
        }

      //重定向超过20次,不再重定向
        if (++followUpCount > MAX_FOLLOW_UPS) {
          throw ProtocolException("Too many follow-up requests: $followUpCount")
        }

        request = followUp
        priorResponse = response
      } finally {
        call.exitNetworkInterceptorExchange(closeActiveExchange)
      }
    }
  }

private fun recover(
    e: IOException,
    call: RealCall,
    userRequest: Request,
    requestSendStarted: Boolean
  ): Boolean {
    // The application layer has forbidden retries.
// 1, okhttp builder的时候设置了 retryOnConnectionFailure(false)
    if (!client.retryOnConnectionFailure) return false 

    // We can't send the request body again. 
  //2,这次请求只请求一次
    if (requestSendStarted && requestIsOneShot(e, userRequest)) return false

    // This exception is fatal.
  //3,判断错误类型,比如io关闭,这种错误不会重试
    if (!isRecoverable(e, requestSendStarted)) return false
 //4,服务器返回了retryAfter
    // No more routes to attempt.
    if (!call.retryAfterFailure()) return false

    // For failure recovery, use the same route selector with a new connection.
    return


 private fun followUpRequest(userResponse: Response, exchange: Exchange?): Request? {
    val route = exchange?.connection?.route()
    val responseCode = userResponse.code

    val method = userResponse.request.method
    when (responseCode) {
    //这俩都是身份验证
      HTTP_PROXY_AUTH -> {
       
        return client.proxyAuthenticator.authenticate(route, userRes ponse)
      }

      HTTP_UNAUTHORIZED -> return client.authenticator.authenticate(route, userResponse)
      //响应重定向,拿出头里location的地址进行重新请求
      HTTP_PERM_REDIRECT, HTTP_TEMP_REDIRECT, HTTP_MULT_CHOICE, HTTP_MOVED_PERM, HTTP_MOVED_TEMP, HTTP_SEE_OTHER -> {
        return buildRedirectRequest(userResponse, method)
      }

    //
      HTTP_CLIENT_TIMEOUT -> {
        // 408's are rare in practice, but some servers like HAProxy use this response code. The
        // spec says that we may repeat the request without modifications. Modern browsers also
        // repeat the request (even non-idempotent ones.)
        if (!client.retryOnConnectionFailure) {
          // The application layer has directed us not to retry the request.
          return null
        }

        val requestBody = userResponse.request.body
        if (requestBody != null && requestBody.isOneShot()) {
          return null
        }
        val priorResponse = userResponse.priorResponse
        //注意这里,连续两次超时,不会再请求
        if (priorResponse != null && priorResponse.code == HTTP_CLIENT_TIMEOUT) {
          // We attempted to retry and got another timeout. Give up.
          return null
        }
    // 要求 retryAfter
        if (retryAfter(userResponse, 0) > 0) {
          return null
        }

        return userResponse.request
      }


      HTTP_UNAVAILABLE -> {
        val priorResponse = userResponse.priorResponse
// 连续 俩次 HTTP_UNAVAILABLE
        if (priorResponse != null && priorResponse.code == HTTP_UNAVAILABLE) {
          // We attempted to retry and got another timeout. Give up.
          return null
        }

//同样retryAfter,需要获取0 
        if (retryAfter(userResponse, Integer.MAX_VALUE) == 0) {
          // specifically received an instruction to retry without delay
          return userResponse.request
        }

        return null
      }
    //重新选择ip请求,比如这个ip 已经满了
      HTTP_MISDIRECTED_REQUEST -> {
        // OkHttp can coalesce HTTP/2 connections even if the domain names are different. See
        // RealConnection.isEligible(). If we attempted this and the server returned HTTP 421, then
        // we can retry on a different connection.
        val requestBody = userResponse.request.body
        if (requestBody != null && requestBody.isOneShot()) {
          return null
        }

        if (exchange == null || !exchange.isCoalescedConnection) {
          return null
        }

        exchange.connection.noCoalescedConnections()
        return userResponse.request
      }

      else -> return null
    }
  }

桥接拦截器 BridgeInterceptor

就是加头,content-type ,content-length,Accept-Encoding ,cookie这些
注意cookie okhttp提供我们保存重用的方法

   new OkHttpClient.Builder().cookieJar(new CookieJar() {
            @Override
            public void saveFromResponse(@NonNull HttpUrl httpUrl, @NonNull List list) {
                
            }

            @NonNull
            @Override
            public List loadForRequest(@NonNull HttpUrl httpUrl) {
                return null;
            }
        })

缓存拦截器

强缓存
就是我能通过时间自己判断要不要实用缓存
代表使用
etag :过期时间
cache - control :max-age
协商缓存 我必须和服务器协商,问下服务器我能不能用这个缓存
代表使用cache - control if-none-match = 上次拿到的 etag, if-modify-since = 上次拿到的lastmodify的值
如果没有变,不会返回新的数据,直接返回304
整个流程
先找有没有缓存 -> 判断上次缓存头类型 -》 判断用户这次请求是否请求缓存 比如用户设置了no-cache, if-modify-since 这些事协商缓存,那就直接请求网络 -> 判断缓存的有效性

链接拦截器

复用之前socket,必须要是信息全部一样,如ip端口http协议
最大支持5个空闲连接,空闲连接最多维持5分钟
新的连接会
1,会生成一个代理
普通代理 socket http
隧道代理 https,这个只能做纯转发,建立连接前需要先发一个connect
2,SSLSocket 可以通过这个建立ssl连接,通过alpn获取当前支持http1还是http2
3,通过系统默认的InetAddress 就能进行 dns解析,但是这个一般都是localdns 也就是接入运行商的,反馈比较慢,还容易被劫持。

      thread {
            val ip2: InetAddress = InetAddress.getByName("www.baidu.com")
            Log.d("wwwwwww","ip2:"+ip2.getHostAddress())
            Log.d("wwwwwww","ip2:"+ip2.getHostName())
        }

请求服务拦截器

就是直接请求网络

问题1,okhttp拦截器怎么复用tcp连接

他有个缓存池RealConnectionPool 里面有个容器缓存了 RealConnection
必须连接信息完全一样才可以用
同时有定时清理机制最大空闲不超过5个,最大空闲时间不超过5分钟

Transfer-Encoding: chunked

分块传输,最后一块长度为0表示结束,因此不需要content-length

你可能感兴趣的:(2022-03-06)