OkHttp源码分析(二)

562 阅读9分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第37天,点击查看活动详情

文章中源码的OkHttp版本为4.10.0

implementation 'com.squareup.okhttp3:okhttp:4.10.0'

OkHttp源码分析(一)中主要分析了使用、如何创建,再到发起请求,这篇文章主要来分析OkHttp的拦截器链。

1.拦截器链

  • 前面的代码在发起请求的时候代码走到了getResponseWithInterceptorChain(),这个方法得到了response的响应,他做了什么呢,先看源码
@Throws(IOException::class)
internal fun getResponseWithInterceptorChain(): Response {
    //构建了一个完整的拦截器栈
    val interceptors = mutableListOf<Interceptor>()
    //用户自定义的拦截器
    interceptors += client.interceptors
    interceptors += RetryAndFollowUpInterceptor(client)
    interceptors += BridgeInterceptor(client.cookieJar)
    interceptors += CacheInterceptor(client.cache)
    interceptors += ConnectInterceptor
    if (!forWebSocket) {
        //用户自定义的网络拦截器
        interceptors += client.networkInterceptors
    }
    //默认的拦截器
    interceptors += CallServerInterceptor(forWebSocket)

    //定义真正的拦截器链
    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 {
        //责任链的关键一行,开启了责任链的传递,责任链中的拦截器层层调用然后层层返回
        val response = chain.proceed(originalRequest)
        //责任链全部执行完毕并且不会出现错误才会调用到这里
        if (isCanceled) {
            response.closeQuietly()
            throw IOException("Canceled")
        }
        return response
    } catch (e: IOException) {
        calledNoMoreExchanges = true
        throw transmitter.noMoreExchanges(e) as Throwable
    } finally {
        if (!calledNoMoreExchanges) {
            noMoreExchanges(null)
        }
    }
}

getResponseWithInterceptorChain方法是整个OkHttp实现责任链模式的核心,在这个方法中除了众多拦截器是重点之外还有chain.proceed这个重点,这里利用了责任链模式,先看一下这里面做了什么事情:

override fun proceed(request: Request): Response {
    check(index < interceptors.size)

    //统计当前拦截器调用proceed方法的次数
    calls++

    //这里是对拦截器调用proceed方法的限制,
    //在ConnectInterceptor及其之后的拦截器最多只能调用一次proceed!!
    if (exchange != null) {
        check(exchange.finder.sameHostAndPort(request.url)) {
        	"network interceptor ${interceptors[index - 1]} must retain the same host and port"
    	}
        check(calls == 1) {
        	"network interceptor ${interceptors[index - 1]} must call proceed() exactly once"
        }
    }
    
    //创建并调用链中的下一个拦截器
    val next = copy(index = index + 1, request = request)
    val interceptor = interceptors[index]
    
    @Suppress("USELESS_ELVIS")
    val response = interceptor.intercept(next) ?: throw NullPointerException(
    "interceptor $interceptor returned null")
    
    if (exchange != null) {
        //保证在ConnectInterceptor及其之后的拦截器至少调用一次proceed!!
        check(index + 1 >= interceptors.size || next.calls == 1) {
        	"network interceptor $interceptor must call proceed() exactly once"
        }
    }
    
    check(response.body != null) { "interceptor $interceptor returned a response with no body" }
    
    return response
}

上面的proceed函数中的逻辑就做了一件事,创建下一级责任链并调用下一个拦截器,在getResponseWithInterceptorChain函数中除CallServerInterceptor拦截器之外它前面的每一个拦截器都会调用一次proceed并且只会调用一次,call++的目的是为了保证责任链能依次调用。

下面再来聊一聊拦截器,如果没有自定义的拦截器那么就只有5个拦截器,这5个拦截器的功能如下图

1.RetryAndFollowUpInterceptor:

  • 重定向或者重试拦截器,同时还创建了一个连接管理池
class RetryAndFollowUpInterceptor(private val client: OkHttpClient) : Interceptor {

    companion object {
        //定义重试或者重定向的次数
        //Chrome遵循21个重定向;Firefox, curl和wget跟随20;Safari是16;HTTP/1.0推荐5。
        private const val MAX_FOLLOW_UPS = 20
    }

    @Throws(IOException::class)
    override fun intercept(chain: Interceptor.Chain): Response {
        //chain转换为具体的拦截器链,RealInterceptorChain实现了Interceptor.Chain
        val realChain = chain as RealInterceptorChain
        var request = chain.request
        //这个call就是RealCall对象
        val call = realChain.call
        var followUpCount = 0
        var priorResponse: Response? = null
        //不是重试并且可以执行新的路由
        var newExchangeFinder = true
        var recoveredFailures = listOf<IOException>()
        while (true) {
            //newExchangeFinder定义为true因此通过enterNetworkInterceptorExchange函数中
            //创建了一个新的ExchangeFinder对象,用来管理连接池
            call.enterNetworkInterceptorExchange(request, newExchangeFinder)

            var response: Response
            var closeActiveExchange = true
            try {
            	if (call.isCanceled()) {
            	throw IOException("Canceled")
            }

            try {
                //责任链,向下传递,让下一个拦截器处理
            	response = realChain.proceed(request)
            	newExchangeFinder = true
            } catch (e: RouteException) {
            	// 通过路由连接失败。请求将不会被发送。
            	if (!recover(e.lastConnectException, call, request, requestSendStarted = false)) {
            		throw e.firstConnectException.withSuppressed(recoveredFailures)
            	} else {
            		recoveredFailures += e.firstConnectException
            	}
            	newExchangeFinder = false
            	continue
            } catch (e: IOException) {
            	// 试图与服务器通信失败。请求可能已经发送。
            	if (!recover(e, call, request, requestSendStarted = e !is ConnectionShutdownException)) {
            		throw e.withSuppressed(recoveredFailures)
            	} else {
            		recoveredFailures += e
            	}
            	newExchangeFinder = false
            	continue
            }

            //后面的处理都结束之后会回传response
            //如果存在,请附上先前的response。这样的response是没有主体的。
            if (priorResponse != null) {
            	response = response.newBuilder()
            		.priorResponse(priorResponse.newBuilder()
            			.body(null)
            			.build())
            		.build()
            }    

			val exchange = call.interceptorScopedExchange

            //找出要响应接收response的HTTP请求。
            //这将添加身份验证头,遵循重定向或处理客户端请求超时。
            //如果后续操作是不必要的或不适用的,则返回null。
        	val followUp = followUpRequest(response, exchange)

        	//获取到的request为空则直接返回response
            if (followUp == null) {
            	if (exchange != null && exchange.isDuplex) {
            		call.timeoutEarlyExit()
            	}
            	closeActiveExchange = false
            	return response
            }

            val followUpBody = followUp.body
            //request有值且只允许被调用一次则返回response
            if (followUpBody != null && followUpBody.isOneShot()) {
                closeActiveExchange = false
          		return response
            }

            response.body?.closeQuietly()

            //超过最大重试或者重定向次数则抛出异常
            if (++followUpCount > MAX_FOLLOW_UPS) {
                throw ProtocolException("Too many follow-up requests: $followUpCount")
            }

            //返回的request若不为空则重新赋值后继续发起请求
            request = followUp
            priorResponse = response
        } finally {
            //如果closeActiveExchange为true则当前交换不被使用且关闭
        	call.exitNetworkInterceptorExchange(closeActiveExchange)
		}
    }
}
 fun enterNetworkInterceptorExchange(request: Request, newExchangeFinder: Boolean) {
    check(interceptorScopedExchange == null)

    synchronized(this) {
        //判断之前的请求是否是打开状态,如果是则不能发出新的请求
		check(!responseBodyOpen) {
			"cannot make a new request because the previous response is still open: " +
			"please call response.close()"
		}
		check(!requestBodyOpen)
	}

    if (newExchangeFinder) {
        //创建了ExChangeFinder
		this.exchangeFinder = ExchangeFinder(
			connectionPool,
			createAddress(request.url),
          	this,
          	eventListener
      	)
    }
}
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 -> {
            //407异常处理
		}
      
		HTTP_UNAUTHORIZED -> {
            //401异常处理
        }
    
        HTTP_PERM_REDIRECT, HTTP_TEMP_REDIRECT, HTTP_MULT_CHOICE, HTTP_MOVED_PERM, HTTP_MOVED_TEMP, HTTP_SEE_OTHER -> {
        	//300 异常处理
            //构建重定向请求
            return buildRedirectRequest(userResponse, method)
        }

        HTTP_CLIENT_TIMEOUT -> {
        	//408异常处理
        }

        HTTP_UNAVAILABLE -> {
            //503异常处理
        }

        HTTP_MISDIRECTED_REQUEST -> {
            //OkHttp可以合并HTTP/2连接,即使域名不同。看到
			//RealConnection.isEligible()。如果我们尝试这样做,并且服务器返回HTTP 421,
            //那么可以尝试另一个连接。
        }
    }
}
/**
 * 构建重定向请求
 */
private fun buildRedirectRequest(userResponse: Response, method: String): Request? {
    // 客户端是否允许重定向?
    if (!client.followRedirects) return null

    val location = userResponse.header("Location") ?: return null
    // 不要遵循重定向到不支持的协议。
    val url = userResponse.request.url.resolve(location) ?: return null

    // 如果配置了,不要遵循SSL和非SSL之间的重定向
    val sameScheme = url.scheme == userResponse.request.url.scheme
    if (!sameScheme && !client.followSslRedirects) return null

    // 大多数重定向不包括请求体。
    val requestBuilder = userResponse.request.newBuilder()
    if (HttpMethod.permitsRequestBody(method)) {
        val responseCode = userResponse.code
        val maintainBody = HttpMethod.redirectsWithBody(method) ||
                responseCode == StatusLine.HTTP_PERM_REDIRECT ||
                responseCode == StatusLine.HTTP_TEMP_REDIRECT
        if (HttpMethod.redirectsToGet(method) && responseCode != StatusLine.HTTP_PERM_REDIRECT && responseCode != StatusLine.HTTP_TEMP_REDIRECT) {
            requestBuilder.method("GET", null)
        } else {
            val requestBody = if (maintainBody) userResponse.request.body else null
            requestBuilder.method(method, requestBody)
        }
        if (!maintainBody) {
            requestBuilder.removeHeader("Transfer-Encoding")
            requestBuilder.removeHeader("Content-Length")
            requestBuilder.removeHeader("Content-Type")
        }
    }

    //当跨主机重定向时,删除所有身份验证头。
    //这对应用层来说是潜在的麻烦,因为他们没有办法保留它们。
    if (!userResponse.request.url.canReuseConnectionFor(url)) {
        requestBuilder.removeHeader("Authorization")
    }

    return requestBuilder.url(url).build()
}

2.BridgeInterceptor:

  • 桥接拦截器,负责把用户请求转换成网络请求,把网络响应转换成对用户友好的响应。
  • 源码方面没什么难度就是添加了一些请求头,需要注意的是Accept-Encoding请求头,如果用户自己添加了那就需要自己解压,如果用户没有添加则请求过程会自己添加gizp,同时会自动解压。

3.CacheInterceptor:

  • CacheInterceptor就是负责更新和读取缓存的,内部是通过okio进行读取和写入的
class CacheInterceptor(internal val cache: Cache?) : Interceptor {

    @Throws(IOException::class)
    override fun intercept(chain: Interceptor.Chain): Response {
        val call = chain.call()
        //获取候选缓存
        val cacheCandidate = cache?.get(chain.request())

        val now = System.currentTimeMillis()

        //获取缓存策略,强制缓存、对比缓存等
        val strategy = CacheStrategy.Factory(now, chain.request(), cacheCandidate).compute()
        val networkRequest = strategy.networkRequest
        val cacheResponse = strategy.cacheResponse

        cache?.trackResponse(strategy)
        val listener = (call as? RealCall)?.eventListener ?: EventListener.NONE

        if (cacheCandidate != null && cacheResponse == null) {
            // 候选缓存不适用,关闭
            cacheCandidate.body?.closeQuietly()
        }

        // 如果网络被禁止使用则缓存为空并且抛出异常504
        if (networkRequest == null && cacheResponse == null) {
            return Response.Builder()
            .request(chain.request())
            .protocol(Protocol.HTTP_1_1)
            .code(HTTP_GATEWAY_TIMEOUT)
            .message("Unsatisfiable Request (only-if-cached)")
            .body(EMPTY_RESPONSE)
            .sentRequestAtMillis(-1L)
            .receivedResponseAtMillis(System.currentTimeMillis())
            .build().also {
            	listener.satisfactionFailure(call, it)
            }
        }

        // 如果不需要网络则直接返回缓存即可
        if (networkRequest == null) {
            return cacheResponse!!.newBuilder()
            .cacheResponse(stripBody(cacheResponse))
            .build().also {
            	listener.cacheHit(call, it)
            }
        }

        var networkResponse: Response? = null
        try {
            //让下一个拦截器处理
            networkResponse = chain.proceed(networkRequest)
        } finally {
            //防止内存泄露
            if (networkResponse == null && cacheCandidate != null) {
                cacheCandidate.body?.closeQuietly()
            }
        }

        //有缓存
        if (cacheResponse != null) {
            //服务器返回状态码为304则返回缓存结果
            if (networkResponse?.code == HTTP_NOT_MODIFIED) {
                val response = cacheResponse.newBuilder()
                .headers(combine(cacheResponse.headers, networkResponse.headers))
                .sentRequestAtMillis(networkResponse.sentRequestAtMillis)
                .receivedResponseAtMillis(networkResponse.receivedResponseAtMillis)
                .cacheResponse(stripBody(cacheResponse))
                .networkResponse(stripBody(networkResponse))
                .build()
                
                networkResponse.body!!.close()
            
                //在合并头之后更新缓存
               	cache!!.trackConditionalCacheHit()
                cache.update(cacheResponse, response)
                return response.also {
                	listener.cacheHit(call, it)
                }
            } else {
                cacheResponse.body?.closeQuietly()
            }
        }

        //读取网络请求结果
         val response = networkResponse!!.newBuilder()
        	.cacheResponse(stripBody(cacheResponse))
        	.networkResponse(stripBody(networkResponse))
        	.build()

        if (cache != null) {
            if (response.promisesBody() && CacheStrategy.isCacheable(response, networkRequest)) {
                //将请求结果进行缓存
                val cacheRequest = cache.put(response)
                 return cacheWritingResponse(cacheRequest, response).also {
                  	if (cacheResponse != null) {
                    	//只记录条件缓存丢失的日志
                    	listener.cacheMiss(call)
                  	}
        		}
            }

            //缓存无效时清除
            if (HttpMethod.invalidatesCache(networkRequest.method)) {
                try {
                    cache.remove(networkRequest)
                } catch (_: IOException) {
                    // 无法写入缓存
                }
            }
        }

        //返回网络读取的结果
        return response
    }
}

4.ConnectInterceptor:

  • 连接拦截器就是用来建立连接的
//建立连接并继续到下一个拦截程序,网络可以用于返回的响应,也可以使用GET验证缓存的响应。
object ConnectInterceptor : Interceptor {

    @Throws(IOException::class)
    override fun intercept(chain: Interceptor.Chain): Response {
        val realChain = chain as RealInterceptorChain
        //返回一个携带新请求的exchange对象
        //exchange主要作用是发送请求和接收响应的。
        val exchange = realChain.call.initExchange(chain)
        val connectedChain = realChain.copy(exchange = exchange)
        //让下一层拦截器处理,同时将exchange一起传递过去
        return connectedChain.proceed(realChain.request)
    }
}
  • 连接又是如何建立连接的
//查找新连接或池连接以承载即将到来的请求和响应
internal fun initExchange(chain: RealInterceptorChain): Exchange {
    synchronized(this) {
        check(expectMoreExchanges) { "released" }
        check(!responseBodyOpen)
        check(!requestBodyOpen)
    }
    
    val exchangeFinder = this.exchangeFinder!!
    //exchangeFinder是在RetryAndFollowUpInterceptor中创建的
    //找到可用的连接后创建一个新的解码器并返回
    val codec = exchangeFinder.find(client, chain)
    //创建Exchange对象,主要负责发送请求和接收响应的
    val result = Exchange(this, eventListener, exchangeFinder, codec)
    this.interceptorScopedExchange = result
    this.exchange = result
    synchronized(this) {
    	this.requestBodyOpen = true
    	this.responseBodyOpen = true
    }
    
    if (canceled) throw IOException("Canceled")
    return result
}
  • exchangeFinder.find(client, chain)
fun find(
    client: OkHttpClient,
    chain: RealInterceptorChain
): ExchangeCodec {
    try {
        //这里就是查找可用的链接,如果不可用则一直重复查找,知道找到为止
        val resultConnection = findHealthyConnection(
        connectTimeout = chain.connectTimeoutMillis,
        readTimeout = chain.readTimeoutMillis,
        writeTimeout = chain.writeTimeoutMillis,
        pingIntervalMillis = client.pingIntervalMillis,
        connectionRetryEnabled = client.retryOnConnectionFailure,
        doExtensiveHealthChecks = chain.request.method != "GET"
        )
        //创建并返回一个新的编码器
        return resultConnection.newCodec(client, chain)
    } catch (e: RouteException) {
    	trackFailure(e.lastConnectException)
    	throw e
    } catch (e: IOException) {
    	trackFailure(e)
    	throw RouteException(e)
    }
}
  • exchangeFinder.findHealthyConnection
@Throws(IOException::class)
private fun findHealthyConnection(
    connectTimeout: Int,
    readTimeout: Int,
    writeTimeout: Int,
    pingIntervalMillis: Int,
    connectionRetryEnabled: Boolean,
    doExtensiveHealthChecks: Boolean
): RealConnection {
    while (true) {
        //查找连接,如果现有连接存在,则优先选择现有连接,然后是池,最后构建一个新连接。
        val candidate = findConnection(
            connectTimeout = connectTimeout,
            readTimeout = readTimeout,
            writeTimeout = writeTimeout,
            pingIntervalMillis = pingIntervalMillis,
            connectionRetryEnabled = connectionRetryEnabled
        )
        
        //确认找到的连接是否可以正常使用
        if (candidate.isHealthy(doExtensiveHealthChecks)) {
        	return candidate
        }
        
        //如果连接不可用就从连接池中取出
        candidate.noNewExchanges()
        
        //这里就是确保连接可用,如果前面找到的连接不可用那么继续查找
        if (nextRouteToTry != null) continue
        
        val routesLeft = routeSelection?.hasNext() ?: true
        if (routesLeft) continue
        
        val routesSelectionLeft = routeSelector?.hasNext() ?: true
        if (routesSelectionLeft) continue
        
        throw IOException("exhausted all routes")
    }
}
  • exchangeFinder.findConnection
@Throws(IOException::class)
private fun findConnection(
    connectTimeout: Int,
    readTimeout: Int,
    writeTimeout: Int,
    pingIntervalMillis: Int,
    connectionRetryEnabled: Boolean
): RealConnection {
	//尝试重用调用中的连接。
    val callConnection = call.connection 
    if (callConnection != null) {
		var toClose: Socket? = null
    	synchronized(callConnection) {
    	if (callConnection.noNewExchanges || !sameHostAndPort(callConnection.route().address.url)) {
      		toClose = call.releaseConnectionNoEvents()
    	}
    }
    
    	//如果连接还没有被释放则重用
        if (call.connection != null) {
        	check(toClose == null)
        	return callConnection
        }
    
    	//连接被释放
    	toClose?.closeQuietly()
        //从连接的分配列表中删除
    	eventListener.connectionReleased(call, callConnection)
    }

    //需要一个新的连接。给它新的数据。
	refusedStreamCount = 0
    connectionShutdownCount = 0
    otherFailureCount = 0

    //从连接池获取
    if (connectionPool.callAcquirePooledConnection(address, call, null, false)) {
    	val result = call.connection!!
    	eventListener.connectionAcquired(call, result)
    	return result
    }

    //连接池中什么都没有的情况下走这里
    val routes: List<Route>?
    val route: Route
    if (nextRouteToTry != null) {
      	//使用来自前一个合并连接的路由
		routes = null
      	route = nextRouteToTry!!
      	nextRouteToTry = null
    } else if (routeSelection != null && routeSelection!!.hasNext()) {
      	// 在现有路由中选择
      	routes = null
      	route = routeSelection!!.next()
    } else {
      	//计算出一个新的连接,这是一个阻塞操作
      	var localRouteSelector = routeSelector
      	if (localRouteSelector == null) {
        	localRouteSelector = RouteSelector(address, call.client.routeDatabase, call, eventListener)
        	this.routeSelector = localRouteSelector
      	}
      	val localRouteSelection = localRouteSelector.next()
      	routeSelection = localRouteSelection
      	routes = localRouteSelection.routes

      	if (call.isCanceled()) throw IOException("Canceled")

      	//这里有了一组新的IP地址,所以再次尝试从连接池中获取
      	if (connectionPool.callAcquirePooledConnection(address, call, routes, false)) {
        	val result = call.connection!!
        	eventListener.connectionAcquired(call, result)
        	return result
      	}

      	route = localRouteSelection.next()
    }

    //创建一个新的连接
    val newConnection = RealConnection(connectionPool, route)
    call.connectionToCancel = newConnection
    try {
        //这里连接了服务器
        newConnection.connect(
            connectTimeout,
            readTimeout,
            writeTimeout,
            pingIntervalMillis,
            connectionRetryEnabled,
            call,
            eventListener
        )
    } finally {
    	call.connectionToCancel = null
    }
    call.client.routeDatabase.connected(newConnection.route())
    
    if (connectionPool.callAcquirePooledConnection(address, call, routes, true)) {
        val result = call.connection!!
        nextRouteToTry = route
        newConnection.socket().closeQuietly()
        eventListener.connectionAcquired(call, result)
        return result
    }
    
    synchronized(newConnection) {
        //添加到连接池中
    	connectionPool.put(newConnection)
    	call.acquireConnectionNoEvents(newConnection)
    }
    
    eventListener.connectionAcquired(call, newConnection)
    return newConnection
}
  • exchangeFinder.find开始到exchangeFinder.findConnection只做了一件事,就是先尝试重用连接,如果不能重用就从连接池中取出一个新的连接,如果无法取出一个连接就创建一个新的连接并添加到连接池中。
  • 服务器是怎么连接的,看这行代码newConnection.connect
fun connect(
    connectTimeout: Int,
    readTimeout: Int,
    writeTimeout: Int,
    pingIntervalMillis: Int,
    connectionRetryEnabled: Boolean,
    call: Call,
    eventListener: EventListener
) {
   ...
    while (true) {
        try {
            if (route.requiresTunnel()) {
            	connectTunnel(connectTimeout, readTimeout, writeTimeout, call, eventListener)
            	if (rawSocket == null) {
                    //无法连接
                    break
                }
            } else {
                //在socket上构建完整HTTP或HTTPS连接
                connectSocket(connectTimeout, readTimeout, call, eventListener)
            }
            establishProtocol(connectionSpecSelector, pingIntervalMillis, call, eventListener)
        	eventListener.connectEnd(call, route.socketAddress, route.proxy, protocol)
            break
        } catch (e: IOException) {
           ...
    }

   ...
}
  • connect中最终调用的是connectSocket方法
@Throws(IOException::class)
private fun connectSocket(
    connectTimeout: Int,
    readTimeout: Int,
    call: Call,
    eventListener: EventListener
) {
    val proxy = route.proxy
    val address = route.address

    //创建socket对象
    val rawSocket = when (proxy.type()) {
		Proxy.Type.DIRECT, Proxy.Type.HTTP -> address.socketFactory.createSocket()!!
      	else -> Socket(proxy)
    }
    this.rawSocket = rawSocket

    eventListener.connectStart(call, route.socketAddress, proxy)
    rawSocket.soTimeout = readTimeout
    try {
        //进行socket连接
        Platform.get().connectSocket(rawSocket, route.socketAddress, connectTimeout)
    } catch (e: ConnectException) {
        throw ConnectException("Failed to connect to ${route.socketAddress}").apply {
            initCause(e)
        }
    }

    try {
        //okio的接口,用于输入,类似InputStream
        source = rawSocket.source().buffer()
        //okio的接口,用于输出,类似OutputStream
        sink = rawSocket.sink().buffer()
    } catch (npe: NullPointerException) {
        if (npe.message == NPE_THROW_WITH_NULL) {
            throw IOException(npe)
        }
    }
}
  • 这个方法就是创建了一个socket对象然后使用socket建立连接,利用okio的输入输出接口获取输入/输出流

5.CallServerInterceptor:

  • 请求拦截器,在前置准备工作完成后,真正发起了网络请求。
  • 先写入请求头,如果是GET请求则请求完毕,如果是POST请求则等待返回状态码为100时在发送请求体
  • 然后读取响应头,经过判断后(非空响应体)再读取响应体
  • 拿到最终结果后一层层的向上传递,会经过之前的每一个拦截器最终回到自己定义的回调中

6.拦截器的总结:

  • 首先经过RetryAndFollowUpIntercept拦截器,它主要负责重试和重定向,并且重试或者重定向的次数不能大于20次,同时它还创建了一个ExchangeFinder对象用于管理连接池为后续的连接做准备;
  • 第二个拦截器是BridgeInterceptor拦截器,这个拦截器主要是补充了请求头,把用户请求转换成网络请求,网络响应转换成用户可以接收的响应,同时还需要注意的一点是如果用户手动添加了Accept-Encoding那就需要处理解压操作;
  • 第三个拦截器是CacheInterceptor拦截器,主要作用就是缓存response并且它的内部是通过okio来处理缓存的;
  • 第四个拦截器是ConnectInterceptor拦截器,这个拦截器是负责建立连接的,从代码中可知最终是通过RealConnection对象建立socket连接的并且获得了输入输出流为下一步读写做准备,RealConnection对象的获取时优先复用的,如果无法复用则从连接池中获取,如果无法获取则创建一个新的连接并将其放入连接池中;
  • 第五个拦截器是CallServerInterceptor拦截器,它真正发起了网络请求,负责数据的读取和写入。