OkHttp
OkHttp是什么?
用于简化Android网络编程的开源框架
推荐前提阅读:Android基础——网络编程
OkHttp使用
依赖
implementation 'com.squareup.okhttp3:okhttp:5.0.0-alpha.14'
权限
<uses-permission android:name="android.permission.INTERNET" />
get
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<Button
android:id="@+id/send_request"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="send_request" />
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/response_text"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</ScrollView>
</LinearLayout>
修改MainAcitivity:
- 创建OkHttpClient
- 创建Request添加相关参数(网址、响应时间)传入OkHttpClient的newCall()方法中,并调用enqueue()添加回调方法
- 调用Response的body()和string()方法获取字符串
public class MainActivity extends AppCompatActivity {
private TextView responseText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
responseText = findViewById(R.id.response_text);
Button sendRequest = findViewById(R.id.send_request);
sendRequest.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
sendRequestWithOkHttp();
}
});
}
private void sendRequestWithOkHttp() {
new Thread(new Runnable() {
@Override
public void run() {
sendOkHttpRequest("https://www.baidu.com", new Callback() {
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) {
e.printStackTrace();
}
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
showResponse(response.body().string());
}
});
}
}).start();
}
public void sendOkHttpRequest(String address, okhttp3.Callback callback) {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url(address)
.build();
client.newCall(request).enqueue(callback);
}
private void showResponse(final String toString) {
runOnUiThread(new Runnable() {
@Override
public void run() {
responseText.setText(toString);
}
});
}
}
post
使用post需创建RequestBody对象并传入到Request的post()方法:
RequestBody requestBody=new FormBody.Builder()
.add("username","admin")
.add("password","123456")
.build();
Request request = new Request.Builder()
.url("https://www.baidu.com")
.post(requestBody)
.build();
OkHttp源码解析
Call
Call中Factory的newCall()接收一个Request,并返回Call
- execute() 同步调用,会阻塞直到Response返回或出错
- enqueue() 异步调用,需要传入回调
interface Call : Cloneable {
fun request(): Request
@Throws(IOException::class)
fun execute(): Response
fun enqueue(responseCallback: Callback)
fun isExecuted(): Boolean
fun isCanceled(): Boolean
fun timeout(): Timeout
public override fun clone(): Call
fun interface Factory {
fun newCall(request: Request): Call
}
}
Callback
异步调用回调通知
- 失败时的参数为当前Call和异常
- 成功时的参数为当前Call和Response
interface Callback {
fun onFailure(
call: Call,
e: IOException,
)
@Throws(IOException::class)
fun onResponse(
call: Call,
response: Response,
)
}
Request
通过Build设置url、header等
class Request internal constructor(builder: Builder) {
......
constructor(
url: HttpUrl,
headers: Headers = headersOf(),
body: RequestBody? = null,
) : this(
Builder()
.url(url)
.headers(headers)
.method(
when {
method != "\u0000" -> method
body != null -> "POST"
else -> "GET"
},
body,
),
)
......
fun newBuilder(): Builder = Builder(this)
......
open class Builder {
internal var url: HttpUrl? = null
internal var method: String
internal var headers: Headers.Builder
internal var body: RequestBody? = null
internal var cacheUrlOverride: HttpUrl? = null
constructor() {
this.method = "GET"
this.headers = Headers.Builder()
}
internal constructor(request: Request) {
this.url = request.url
this.method = request.method
this.body = request.body
this.tags =
when {
request.tags.isEmpty() -> mapOf()
else -> request.tags.toMutableMap()
}
this.headers = request.headers.newBuilder()
this.cacheUrlOverride = request.cacheUrlOverride
}
open fun url(url: HttpUrl): Builder =
apply {
this.url = url
}
open fun url(url: String): Builder {
return url(canonicalUrl(url).toHttpUrl())
}
open fun url(url: URL) = url(url.toString().toHttpUrl())
open fun header(
name: String,
value: String,
) = commonHeader(name, value)
open fun addHeader(
name: String,
value: String,
) = commonAddHeader(name, value)
......
open fun build(): Request = Request(this)
}
}
Response
通过Build设置code、body等
class Response internal constructor(.....) : Closeable {
open class Builder {
internal var request: Request? = null
internal var protocol: Protocol? = null
internal var code = -1
internal var message: String? = null
internal var handshake: Handshake? = null
internal var headers: Headers.Builder
internal var body: ResponseBody = commonEmptyResponse
internal var networkResponse: Response? = null
internal var cacheResponse: Response? = null
internal var priorResponse: Response? = null
internal var sentRequestAtMillis: Long = 0
internal var receivedResponseAtMillis: Long = 0
internal var exchange: Exchange? = null
internal var trailersFn: (() -> Headers) = { Headers.headersOf() }
constructor() {
headers = Headers.Builder()
}
internal constructor(response: Response) {
this.request = response.request
this.protocol = response.protocol
this.code = response.code
this.message = response.message
this.handshake = response.handshake
this.headers = response.headers.newBuilder()
this.body = response.body
this.networkResponse = response.networkResponse
this.cacheResponse = response.cacheResponse
this.priorResponse = response.priorResponse
this.sentRequestAtMillis = response.sentRequestAtMillis
this.receivedResponseAtMillis = response.receivedResponseAtMillis
this.exchange = response.exchange
this.trailersFn = response.trailersFn
}
open fun request(request: Request) = commonRequest(request)
open fun protocol(protocol: Protocol) = commonProtocol(protocol)
open fun code(code: Int) = commonCode(code)
open fun message(message: String) = commonMessage(message)
open fun header(
name: String,
value: String,
) = commonHeader(name, value)
open fun addHeader(
name: String,
value: String,
) = commonAddHeader(name, value)
open fun headers(headers: Headers) = commonHeaders(headers)
open fun body(body: ResponseBody) = commonBody(body)
open fun build(): Response {
check(code >= 0) { "code < 0: $code" }
return Response(
checkNotNull(request) { "request == null" },
checkNotNull(protocol) { "protocol == null" },
checkNotNull(message) { "message == null" },
code,
handshake,
headers.build(),
body,
networkResponse,
cacheResponse,
priorResponse,
sentRequestAtMillis,
receivedResponseAtMillis,
exchange,
trailersFn,
)
}
}
}
OkHttpClient
- 继承Call.Factory重写newCall()
- 继承WebSocket.Factory重写newWebSocket()
open class OkHttpClient internal constructor(
builder: Builder,
) : Call.Factory, WebSocket.Factory {
......
}
构造函数传入默认的Builder,内部创建Dispatcher、connectionPool等
constructor() : this(Builder())
class Builder() {
internal var dispatcher: Dispatcher = Dispatcher()
internal var connectionPool: ConnectionPool? = null
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 fastFallback = true
internal var authenticator: Authenticator = Authenticator.NONE
internal var followRedirects = true
internal var followSslRedirects = true
internal var cookieJar: CookieJar = CookieJar.NO_COOKIES
internal var cache: Cache? = null
internal var dns: Dns = Dns.SYSTEM
internal var proxy: Proxy? = null
internal var proxySelector: ProxySelector? = null
internal var proxyAuthenticator: Authenticator = Authenticator.NONE
internal var socketFactory: SocketFactory = SocketFactory.getDefault()
internal var sslSocketFactoryOrNull: SSLSocketFactory? = null
internal var x509TrustManagerOrNull: X509TrustManager? = null
internal var connectionSpecs: List<ConnectionSpec> = DEFAULT_CONNECTION_SPECS
internal var protocols: List<Protocol> = DEFAULT_PROTOCOLS
internal var hostnameVerifier: HostnameVerifier = OkHostnameVerifier
internal var certificatePinner: CertificatePinner = CertificatePinner.DEFAULT
internal var certificateChainCleaner: CertificateChainCleaner? = null
internal var callTimeout = 0
internal var connectTimeout = 10_000
internal var readTimeout = 10_000
internal var writeTimeout = 10_000
internal var pingInterval = 0
internal var webSocketCloseTimeout = RealWebSocket.CANCEL_AFTER_CLOSE_MILLIS.toInt()
internal var minWebSocketMessageToCompress = RealWebSocket.DEFAULT_MINIMUM_DEFLATE_SIZE
internal var routeDatabase: RouteDatabase? = null
internal var taskRunner: TaskRunner? = null
......
}
newCall()返回RealCall对象
override fun newCall(request: Request): Call = RealCall(this, request, forWebSocket = false)
RealCall
RealCall是Call的实现类,重写了
- execute()调用dispatcher的executed()和finished(),调用getResponseWithInterceptorChain()
- enqueue()将Callback封装成AsyncCall调用dispatcher的enqueue()
class RealCall(
val client: OkHttpClient,
val originalRequest: Request,
val forWebSocket: Boolean,
) : Call, Cloneable {
private val connectionPool: RealConnectionPool = client.connectionPool.delegate
internal val eventListener: EventListener = client.eventListenerFactory.create(this)
private val timeout =
object : AsyncTimeout() {
override fun timedOut() {
this@RealCall.cancel()
}
}.apply {
timeout(client.callTimeoutMillis.toLong(), MILLISECONDS)
}
private val executed = AtomicBoolean()
@Volatile private var canceled = false
override fun timeout(): Timeout = timeout
override fun request(): Request = originalRequest
override fun cancel() {
if (canceled) return // Already canceled.
canceled = true
exchange?.cancel()
for (plan in plansToCancel) {
plan.cancel()
}
eventListener.canceled(this)
}
override fun isCanceled(): Boolean = canceled
override fun execute(): Response {
check(executed.compareAndSet(false, true)) { "Already Executed" }
timeout.enter()
callStart()
try {
client.dispatcher.executed(this)
return getResponseWithInterceptorChain()
} finally {
client.dispatcher.finished(this)
}
}
override fun enqueue(responseCallback: Callback) {
check(executed.compareAndSet(false, true)) { "Already Executed" }
callStart()
client.dispatcher.enqueue(AsyncCall(responseCallback))
}
override fun isExecuted(): Boolean = executed.get()
private fun callStart() {
this.callStackTrace = Platform.get().getStackTraceForCloseable("response.body().close()")
eventListener.callStart(this)
}
.....
}
AsyncCall
继承Runnable,run()中调用getResponseWithInterceptorChain(),回调onResponse()和onFailure()
inner class AsyncCall(
private val responseCallback: Callback,
) : Runnable {
@Volatile var callsPerHost = AtomicInteger(0)
private set
fun reuseCallsPerHostFrom(other: AsyncCall) {
this.callsPerHost = other.callsPerHost
}
val host: String
get() = originalRequest.url.host
val request: Request
get() = originalRequest
val call: RealCall
get() = this@RealCall
/**
* Attempt to enqueue this async call on [executorService]. This will attempt to clean up
* if the executor has been shut down by reporting the call as failed.
*/
fun executeOn(executorService: ExecutorService) {
client.dispatcher.assertThreadDoesntHoldLock()
var success = false
try {
executorService.execute(this)
success = true
} catch (e: RejectedExecutionException) {
failRejected(e)
} finally {
if (!success) {
client.dispatcher.finished(this) // This call is no longer running!
}
}
}
internal fun failRejected(e: RejectedExecutionException? = null) {
val ioException = InterruptedIOException("executor rejected")
ioException.initCause(e)
noMoreExchanges(ioException)
responseCallback.onFailure(this@RealCall, ioException)
}
override fun run() {
threadName("OkHttp ${redactedUrl()}") {
var signalledCallback = false
timeout.enter()
try {
val response = getResponseWithInterceptorChain()
signalledCallback = true
responseCallback.onResponse(this@RealCall, response)
} catch (e: IOException) {
if (signalledCallback) {
// Do not signal the callback twice!
Platform.get().log("Callback failure for ${toLoggableString()}", Platform.INFO, e)
} else {
responseCallback.onFailure(this@RealCall, e)
}
} catch (t: Throwable) {
cancel()
if (!signalledCallback) {
val canceledException = IOException("canceled due to $t")
canceledException.addSuppressed(t)
responseCallback.onFailure(this@RealCall, canceledException)
}
throw t
} finally {
client.dispatcher.finished(this)
}
}
}
}
Dispatcher
executed()
将RealCall添加到同步队列runningSyncCalls
@Synchronized internal fun executed(call: RealCall) {
runningSyncCalls.add(call)
}
enqueue()
将AsyncCall添加到同步队列readyAsyncCalls,根据host判断队列中是否已经存在,调用promoteAndExecute()
@get:Synchronized
@get:JvmName("executorService")
val executorService: ExecutorService
get() {
if (executorServiceOrNull == null) {
executorServiceOrNull =
ThreadPoolExecutor(
0,
Int.MAX_VALUE,
60,
TimeUnit.SECONDS,
SynchronousQueue(),
threadFactory("$okHttpName Dispatcher", false),
)
}
return executorServiceOrNull!!
}
internal fun enqueue(call: AsyncCall) {
synchronized(this) {
readyAsyncCalls.add(call)
if (!call.call.forWebSocket) {
val existingCall = findExistingCallWithHost(call.host)
if (existingCall != null) call.reuseCallsPerHostFrom(existingCall)
}
}
promoteAndExecute()
}
private fun promoteAndExecute(): Boolean {
this.assertThreadDoesntHoldLock()
val executableCalls = mutableListOf<AsyncCall>()
val isRunning: Boolean
synchronized(this) {
val i = readyAsyncCalls.iterator()
while (i.hasNext()) {
val asyncCall = i.next()
if (runningAsyncCalls.size >= this.maxRequests) break // Max capacity.
if (asyncCall.callsPerHost.get() >= this.maxRequestsPerHost) continue // Host max capacity.
i.remove()
asyncCall.callsPerHost.incrementAndGet()
executableCalls.add(asyncCall)
runningAsyncCalls.add(asyncCall)
}
isRunning = runningCallsCount() > 0
}
if (executorService.isShutdown) {
for (i in 0 until executableCalls.size) {
val asyncCall = executableCalls[i]
asyncCall.callsPerHost.decrementAndGet()
synchronized(this) {
runningAsyncCalls.remove(asyncCall)
}
asyncCall.failRejected()
}
idleCallback?.run()
} else {
for (i in 0 until executableCalls.size) {
val asyncCall = executableCalls[i]
asyncCall.executeOn(executorService)
}
}
return isRunning
}
promoteAndExecute()从readyAsyncCalls取出asyncCall添加到runningAsyncCalls,然后判断线程池状态,若已关闭则调用failRejected(),否则调用executeOn()交给线程池(SynchronousQueue可直接将任务从生产者移交给工作者线程)
finish()
从runningSyncCalls移除已执行完的RealCall,调用promoteAndExecute()执行下一个
internal fun finished(call: RealCall) {
finished(runningSyncCalls, call)
}
private fun <T> finished(
calls: Deque<T>,
call: T,
) {
val idleCallback: Runnable?
synchronized(this) {
if (!calls.remove(call)) throw AssertionError("Call wasn't in-flight!")
idleCallback = this.idleCallback
}
val isRunning = promoteAndExecute()
if (!isRunning && idleCallback != null) {
idleCallback.run()
}
}
getResponseWithInterceptorChain()
不管同步还是异步都会调用RealCall中的getResponseWithInterceptorChain()获取数据
- 创建Interceptor封装到RealInterceptorChain,调用其proceed()方法
@Throws(IOException::class)
internal fun getResponseWithInterceptorChain(): Response {
// Build a full stack of interceptors.
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 noMoreExchanges(e) as Throwable
} finally {
if (!calledNoMoreExchanges) {
noMoreExchanges(null)
}
}
}
Interceptor
用于定义拦截规则和构造责任链
fun interface Interceptor {
@Throws(IOException::class)
fun intercept(chain: Chain): Response
companion object {
inline operator fun invoke(crossinline block: (chain: Chain) -> Response): Interceptor = Interceptor { block(it) }
}
interface Chain {
fun request(): Request
@Throws(IOException::class)
fun proceed(request: Request): Response
fun connection(): Connection?
fun call(): Call
fun connectTimeoutMillis(): Int
fun withConnectTimeout(
timeout: Int,
unit: TimeUnit,
): Chain
fun readTimeoutMillis(): Int
fun withReadTimeout(
timeout: Int,
unit: TimeUnit,
): Chain
fun writeTimeoutMillis(): Int
fun withWriteTimeout(
timeout: Int,
unit: TimeUnit,
): Chain
}
}
RealInterceptorChain
- proceed()调用Interceptor子类的intercept()
- 子类的intercept()又会调用下一个Interceptor的proceed()
- 即每个Interceptor子类中在proceed()之前的为拦截代码,在其后的为返回代码
class RealInterceptorChain(
internal val call: RealCall,
private val interceptors: List<Interceptor>,
private val index: Int,
internal val exchange: Exchange?,
internal val request: Request,
internal val connectTimeoutMillis: Int,
internal val readTimeoutMillis: Int,
internal val writeTimeoutMillis: Int,
) : Interceptor.Chain {
private var calls: Int = 0
......
@Throws(IOException::class)
override fun proceed(request: Request): Response {
check(index < interceptors.size)
calls++
......
// Call the next interceptor in the chain.
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",
)
......
return response
}
}
RetryAndFollowUpInterceptor
class RetryAndFollowUpInterceptor(private val client: OkHttpClient) : Interceptor {
@Throws(IOException::class)
override fun intercept(chain: Interceptor.Chain): Response {
val realChain = chain as RealInterceptorChain
var request = chain.request
val call = realChain.call
var followUpCount = 0
var priorResponse: Response? = null
var newRoutePlanner = true
var recoveredFailures = listOf<IOException>()
//通过死循环实现retry或处理下一个request
while (true) {
call.enterNetworkInterceptorExchange(request, newRoutePlanner, chain)
var response: Response
var closeActiveExchange = true
try {
if (call.isCanceled()) {
throw IOException("Canceled")
}
//调用下一个拦截器的proceed()
try {
response = realChain.proceed(request)
newRoutePlanner = true
} catch (e: IOException) {
//若无法恢复则抛出异常,否则通过continue继续尝试
if (!recover(e, call, request, requestSendStarted = e !is ConnectionShutdownException)) {
throw e.withSuppressed(recoveredFailures)
} else {
recoveredFailures += e
}
newRoutePlanner = false
continue
}
//若没有异常则构造response
response =
response.newBuilder()
.request(request)
.priorResponse(priorResponse?.stripBody())
.build()
val exchange = call.interceptorScopedExchange
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
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 = followUp
priorResponse = response
} finally {
call.exitNetworkInterceptorExchange(closeActiveExchange)
}
}
}
......
}
BridgeInterceptor
在这里主要构造request的请求头等信息
class BridgeInterceptor(private val cookieJar: CookieJar) : Interceptor {
@Throws(IOException::class)
override fun intercept(chain: Interceptor.Chain): Response {
val userRequest = chain.request()
val requestBuilder = userRequest.newBuilder()
val body = userRequest.body
if (body != null) {
val contentType = body.contentType()
if (contentType != null) {
requestBuilder.header("Content-Type", contentType.toString())
}
val contentLength = body.contentLength()
if (contentLength != -1L) {
requestBuilder.header("Content-Length", contentLength.toString())
requestBuilder.removeHeader("Transfer-Encoding")
} else {
requestBuilder.header("Transfer-Encoding", "chunked")
requestBuilder.removeHeader("Content-Length")
}
}
if (userRequest.header("Host") == null) {
requestBuilder.header("Host", userRequest.url.toHostHeader())
}
if (userRequest.header("Connection") == null) {
requestBuilder.header("Connection", "Keep-Alive")
}
// If we add an "Accept-Encoding: gzip" header field we're responsible for also decompressing
// the transfer stream.
var transparentGzip = false
if (userRequest.header("Accept-Encoding") == null && userRequest.header("Range") == null) {
transparentGzip = true
requestBuilder.header("Accept-Encoding", "gzip")
}
val cookies = cookieJar.loadForRequest(userRequest.url)
if (cookies.isNotEmpty()) {
requestBuilder.header("Cookie", cookieHeader(cookies))
}
if (userRequest.header("User-Agent") == null) {
requestBuilder.header("User-Agent", USER_AGENT)
}
val networkRequest = requestBuilder.build()
val networkResponse = chain.proceed(networkRequest)
cookieJar.receiveHeaders(networkRequest.url, networkResponse.headers)
val responseBuilder =
networkResponse.newBuilder()
.request(networkRequest)
if (transparentGzip &&
"gzip".equals(networkResponse.header("Content-Encoding"), ignoreCase = true) &&
networkResponse.promisesBody()
) {
val responseBody = networkResponse.body
if (responseBody != null) {
val gzipSource = GzipSource(responseBody.source())
val strippedHeaders =
networkResponse.headers.newBuilder()
.removeAll("Content-Encoding")
.removeAll("Content-Length")
.build()
responseBuilder.headers(strippedHeaders)
val contentType = networkResponse.header("Content-Type")
responseBuilder.body(RealResponseBody(contentType, -1L, gzipSource.buffer()))
}
}
return responseBuilder.build()
}
CacheInterceptor
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().requestForCache())
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)")
.sentRequestAtMillis(-1L)
.receivedResponseAtMillis(System.currentTimeMillis())
.build().also {
listener.satisfactionFailure(call, it)
}
}
//若没网且缓存不为空,将缓存内容添加到cacheResponse并返回
if (networkRequest == null) {
return cacheResponse!!.newBuilder()
.cacheResponse(cacheResponse.stripBody())
.build().also {
listener.cacheHit(call, it)
}
}
//上面是没网的情况,下面是有网的情况
if (cacheResponse != null) {
listener.cacheConditionalHit(call, cacheResponse)
} else if (cache != null) {
listener.cacheMiss(call)
}
//执行下一个拦截器
var networkResponse: Response? = null
try {
networkResponse = chain.proceed(networkRequest)
} finally {
if (networkResponse == null && cacheCandidate != null) {
cacheCandidate.body.closeQuietly()
}
}
//当前缓存有空间
if (cacheResponse != null) {
if (networkResponse?.code == HTTP_NOT_MODIFIED) {
//304,上次请求后,响应的内容未改变,更新cacheResponse和cache并返回
val response =
cacheResponse.newBuilder()
.headers(combine(cacheResponse.headers, networkResponse.headers))
.sentRequestAtMillis(networkResponse.sentRequestAtMillis)
.receivedResponseAtMillis(networkResponse.receivedResponseAtMillis)
.cacheResponse(cacheResponse.stripBody())
.networkResponse(networkResponse.stripBody())
.build()
networkResponse.body.close()
cache!!.trackConditionalCacheHit()
cache.update(cacheResponse, response)
return response.also {
listener.cacheHit(call, it)
}
} else {
cacheResponse.body.closeQuietly()
}
}
//根据cacheResponse和networkResponse构造新的response并返回
val response =
networkResponse!!.newBuilder()
.cacheResponse(cacheResponse?.stripBody())
.networkResponse(networkResponse.stripBody())
.build()
//写入用户设置的缓存
if (cache != null) {
val cacheNetworkRequest = networkRequest.requestForCache()
if (response.promisesBody() && CacheStrategy.isCacheable(response, cacheNetworkRequest)) {
// Offer this request to the cache.
val cacheRequest = cache.put(response.newBuilder().request(cacheNetworkRequest).build())
return cacheWritingResponse(cacheRequest, response).also {
if (cacheResponse != null) {
// This will log a conditional cache miss only.
listener.cacheMiss(call)
}
}
}
if (HttpMethod.invalidatesCache(networkRequest.method)) {
try {
cache.remove(networkRequest)
} catch (_: IOException) {
// The cache cannot be written.
}
}
}
return response
}
......
}
ConnectInterceptor
初始化Exchange
object ConnectInterceptor : Interceptor {
@Throws(IOException::class)
override fun intercept(chain: Interceptor.Chain): Response {
val realChain = chain as RealInterceptorChain
val exchange = realChain.call.initExchange(realChain)
val connectedChain = realChain.copy(exchange = exchange)
return connectedChain.proceed(realChain.request)
}
}
CallServerInterceptor
通过exchange向服务器发起网络请求,并读取结果
class CallServerInterceptor(private val forWebSocket: Boolean) : Interceptor {
@Throws(IOException::class)
override fun intercept(chain: Interceptor.Chain): Response {
val realChain = chain as RealInterceptorChain
val exchange = realChain.exchange!!
val request = realChain.request
val requestBody = request.body
val sentRequestMillis = System.currentTimeMillis()
var invokeStartEvent = true
var responseBuilder: Response.Builder? = null
var sendRequestException: IOException? = null
try {
exchange.writeRequestHeaders(request)
if (HttpMethod.permitsRequestBody(request.method) && requestBody != null) {
// If there's a "Expect: 100-continue" header on the request, wait for a "HTTP/1.1 100
// Continue" response before transmitting the request body. If we don't get that, return
// what we did get (such as a 4xx response) without ever transmitting the request body.
if ("100-continue".equals(request.header("Expect"), ignoreCase = true)) {
exchange.flushRequest()
responseBuilder = exchange.readResponseHeaders(expectContinue = true)
exchange.responseHeadersStart()
invokeStartEvent = false
}
if (responseBuilder == null) {
if (requestBody.isDuplex()) {
// Prepare a duplex body so that the application can send a request body later.
exchange.flushRequest()
val bufferedRequestBody = exchange.createRequestBody(request, true).buffer()
requestBody.writeTo(bufferedRequestBody)
} else {
// Write the request body if the "Expect: 100-continue" expectation was met.
val bufferedRequestBody = exchange.createRequestBody(request, false).buffer()
requestBody.writeTo(bufferedRequestBody)
bufferedRequestBody.close()
}
} else {
exchange.noRequestBody()
if (!exchange.connection.isMultiplexed) {
// If the "Expect: 100-continue" expectation wasn't met, prevent the HTTP/1 connection
// from being reused. Otherwise we're still obligated to transmit the request body to
// leave the connection in a consistent state.
exchange.noNewExchangesOnConnection()
}
}
} else {
exchange.noRequestBody()
}
if (requestBody == null || !requestBody.isDuplex()) {
exchange.finishRequest()
}
} catch (e: IOException) {
if (e is ConnectionShutdownException) {
throw e // No request was sent so there's no response to read.
}
if (!exchange.hasFailure) {
throw e // Don't attempt to read the response; we failed to send the request.
}
sendRequestException = e
}
try {
if (responseBuilder == null) {
responseBuilder = exchange.readResponseHeaders(expectContinue = false)!!
if (invokeStartEvent) {
exchange.responseHeadersStart()
invokeStartEvent = false
}
}
var response =
responseBuilder
.request(request)
.handshake(exchange.connection.handshake())
.sentRequestAtMillis(sentRequestMillis)
.receivedResponseAtMillis(System.currentTimeMillis())
.build()
var code = response.code
if (shouldIgnoreAndWaitForRealResponse(code, exchange)) {
responseBuilder = exchange.readResponseHeaders(expectContinue = false)!!
if (invokeStartEvent) {
exchange.responseHeadersStart()
}
response =
responseBuilder
.request(request)
.handshake(exchange.connection.handshake())
.sentRequestAtMillis(sentRequestMillis)
.receivedResponseAtMillis(System.currentTimeMillis())
.build()
code = response.code
}
exchange.responseHeadersEnd(response)
response =
if (forWebSocket && code == 101) {
// Connection is upgrading, but we need to ensure interceptors see a non-null response body.
response.stripBody()
} else {
response.newBuilder()
.body(exchange.openResponseBody(response))
.build()
}
if ("close".equals(response.request.header("Connection"), ignoreCase = true) ||
"close".equals(response.header("Connection"), ignoreCase = true)
) {
exchange.noNewExchangesOnConnection()
}
if ((code == 204 || code == 205) && response.body.contentLength() > 0L) {
throw ProtocolException(
"HTTP $code had non-zero Content-Length: ${response.body.contentLength()}",
)
}
return response
} catch (e: IOException) {
if (sendRequestException != null) {
sendRequestException.addSuppressed(e)
throw sendRequestException
}
throw e
}
}
.....
}
本文介绍了OkHttp,Square出品的Android网络库,演示了如何添加依赖、创建请求、执行并解析响应,以及提供OkHttp最佳用法,包括通过OkHttpUtil封装并发请求处理。
2149

被折叠的 条评论
为什么被折叠?



