使用
1. 添加依赖
implementation 'com.squareup.okhttp3:okhttp:3.14.9'
2. 常用请求方法
1. 同步GET请求
1. 创建OkHttpClient对象
- 直接创建
val client = OkHttpClient()
- 通过Builder模式创建
val client = OkHttpClient.Builder()
.build()
2. 创建Request对象
val request = Request.Builder()
.url("https://www.baidu.com")
.get()
.build()
3. 将request封装成call对象
val call = client.newCall(request)
4. 调用call.execute发送同步请求
val response = call.execute()
if (response.isSuccessful) {
log(response.body()?.string())
} else {
log(IOException("Unexpected code $response").message)
}
- 注意:需要在子线程调用,发送请求后,当前线程就会进入阻塞状态,直到收到响应
lifecycleScope.launch {
withContext(Dispatchers.IO) {
getSync()
}
}
<uses-permission android:name="android.permission.INTERNET" />
- 如果是非https请求,可能会报错:java.net.UnknownServiceException: CLEARTEXT communication to。。。
- CLEARTEXT,就是明文的意思,在Android P系统的设备上,如果应用使用的是非加密的明文流量的http网络请求,则会导致该应用无法进行网络请求,
https则不会受影响,同样地,如果应用嵌套了webView,webView也只能使用https请求;
- 解决该异常需要改为https请求,或者在 AndroidManifest.xml文件的Application标签中加入android:usesCleartextTraffic="true"
2. 异步get请求
- 执行请求的操作是非阻塞式的,执行结果通过接口回调方式告知调用者
- 前三步是一样的,第四步调用异步方法 call.enqueue
val client = OkHttpClient()
val request = Request.Builder()
.url("https://www.baidu.com")
.get()
.build()
val call = client.newCall(request)
call.enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
log("onFailure:${e.message}")
runOnUiThread { tv.text = e.message }
}
override fun onResponse(call: Call, response: Response) {
val result = response.body()?.string()
log("onResponse:${result}")
runOnUiThread { tv.text = "onResponse${result}" }
}
})
- 注意:回调方法onResponse,onFailure是在 子线程/工作线程 中执行的, 所以onResponse中使用了runOnUiThread来更新UI;
3. 异步POST请求提交键值对
- 多了一步创建FormBody,为POST请求的参数
val client = OkHttpClient()
val formBody = FormBody.Builder()
.add("k", "wanAndroid")
.build()
val request = Request.Builder()
.url("https://www.wanandroid.com/article/query/0/json")
.post(formBody)
.build()
val call = client.newCall(request)
call.enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
log("onFailure:${e.message}")
runOnUiThread { tv.text = e.message }
}
override fun onResponse(call: Call, response: Response) {
val result = response.body()?.string()
log("onResponse:${result}")
runOnUiThread { tv.text = "onResponse${result}" }
}
})
4. Post方式提交流(上传文件)
private fun postFile() {
val client = OkHttpClient()
val file=File(externalCacheDir,"ljy.txt")
val requestBody=RequestBody.create(
MediaType.parse("text/x-markdown; charset=utf-8"),
file
)
val request=Request.Builder()
.url("https://api.github.com/markdown/raw")
.post(requestBody)
.build()
client.newCall(request).enqueue(object : Callback{
override fun onFailure(call: Call, e: IOException) {
log("onFailure:${e.message}")
}
override fun onResponse(call: Call, response: Response) {
log("onResponse:${ response.body()?.string()}")
}
})
}
- 需要在AndroidManifest.xml中添加读写权限, 和运行时权限申请
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED
&& ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED
) {
this@MainActivity.requestPermissions(arrayOf(
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE), 10001)
} else {
...
}
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == 10001) {
...
}
}
5. 异步下载文件
private fun downloadFile() {
val client = OkHttpClient()
val url = "https://pic3.zhimg.com/v2-dc32dcddfd7e78e56cc4b6f689a24979_xl.jpg"
val request = Request.Builder()
.url(url)
.build()
client.newCall(request).enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
log("onFailure:${e.message}")
}
override fun onResponse(call: Call, response: Response) {
val inputStream = response.body()?.byteStream()
val fileOutputStream = FileOutputStream(File(externalCacheDir, "ljy.jpg"))
val buffer = ByteArray(2048)
var len: Int
while (inputStream?.read(buffer).also { len = it ?: -1 } != -1) {
fileOutputStream.write(buffer, 0, len)
}
fileOutputStream.flush()
log("文件下载成功")
}
})
}
6. Post提交表单
private fun sendMultipart() {
val client = OkHttpClient()
val file = File(externalCacheDir, "ljy.jpg")
val requestBody: RequestBody = MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("name", "ljy")
.addFormDataPart("age", "18")
.addFormDataPart(
"image", "header.jpg",
RequestBody.create(MediaType.parse("image/png"), file)
)
.build()
val request: Request = Request.Builder()
.header("Authorization", "Client-ID " + "...")
.url("https://api.imgur.com/3/image")
.post(requestBody)
.build()
client.newCall(request).enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
log("onFailure:${e.message}")
}
override fun onResponse(call: Call, response: Response) {
log("onResponse:${response.body()?.string()}")
}
})
}
常用设置
1. 设置超时时间
val client = OkHttpClient.Builder()
.connectTimeout(30,TimeUnit.SECONDS)
.readTimeout(60,TimeUnit.SECONDS)
.writeTimeout(90,TimeUnit.SECONDS)
.build()
2. 设置缓存
val client = OkHttpClient.Builder()
.addNetworkInterceptor(CacheInterceptor())
.cache(
Cache(
File(cacheDir, "httpCache2"),
100 * 1024 * 1024L
)
).build()
class CacheInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
var request: Request = chain.request()
val var10000: Response
val response: Response
if (NetUtil.isNetworkAvailable(this@OkHttpDemoActivity)) {
response = chain.proceed(request)
val cacheControl = CacheControl.Builder()
.maxAge(30, TimeUnit.SECONDS)
.build()
.toString()
var10000 = response.newBuilder()
.removeHeader("Pragma")
.removeHeader("Cache-Control")
.header("Cache-Control", cacheControl)
.build()
} else {
request = request.newBuilder()
.cacheControl(CacheControl.FORCE_CACHE)
.build()
var10000 = chain.proceed(request)
}
return var10000
}
}
- OkHttpClient.cache的入参Cache构造函数如下:
public Cache(File directory, long maxSize) {
this(directory, maxSize, FileSystem.SYSTEM);
}
Cache(File directory, long maxSize, FileSystem fileSystem) {
this.cache = DiskLruCache.create(fileSystem, directory, VERSION, ENTRY_COUNT, maxSize);
}
3. 设置失败重试
val client = OkHttpClient.Builder()
.retryOnConnectionFailure(true)
.build()
4. 持久化cookie
implementation 'com.zhy:okhttputils:2.6.2'
val cookieJar = new CookieJarImpl(new PersistentCookieStore(CommonModule.getAppContext()))
val client = OkHttpClient.Builder()
.cookieJar(cookieJar)
.build()
源码解析
Request
- Request.Builder()构造方法如下,method默认是GET
public Builder() {
this.method = "GET"
this.headers = new Headers.Builder()
}
public Request build() {
if (url == null) throw new IllegalStateException("url == null")
return new Request(this)
}
//Request构造方法
Request(Builder builder) {
this.url = builder.url
this.method = builder.method
this.headers = builder.headers.build()
this.body = builder.body
this.tags = Util.immutableMap(builder.tags)
}
- Request.BUilder的post方法如下:
public Builder post(RequestBody body) {
return method("POST", body);
}
public Builder method(String method, @Nullable RequestBody body) {
if (method == null) throw new NullPointerException("method == null");
if (method.length() == 0) throw new IllegalArgumentException("method.length() == 0");
if (body != null && !HttpMethod.permitsRequestBody(method)) {
throw new IllegalArgumentException("method " + method + " must not have a request body.");
}
if (body == null && HttpMethod.requiresRequestBody(method)) {
throw new IllegalArgumentException("method " + method + " must have a request body.");
}
this.method = method;
this.body = body;
return this;
}
OkHttpClient
- OkHttpClient构造方法实现如下:
public OkHttpClient() {
this(new Builder())
}
// builder的构造方法中提供了默认值:
public Builder() {
dispatcher = new Dispatcher()
protocols = DEFAULT_PROTOCOLS
connectionSpecs = DEFAULT_CONNECTION_SPECS
eventListenerFactory = EventListener.factory(EventListener.NONE)
proxySelector = ProxySelector.getDefault()
if (proxySelector == null) {
proxySelector = new NullProxySelector()
}
cookieJar = CookieJar.NO_COOKIES
socketFactory = SocketFactory.getDefault()
hostnameVerifier = OkHostnameVerifier.INSTANCE
certificatePinner = CertificatePinner.DEFAULT
proxyAuthenticator = Authenticator.NONE
authenticator = Authenticator.NONE
connectionPool = new ConnectionPool()
dns = Dns.SYSTEM
followSslRedirects = true
followRedirects = true
retryOnConnectionFailure = true
callTimeout = 0
connectTimeout = 10_000
readTimeout = 10_000
writeTimeout = 10_000
pingInterval = 0
}
public OkHttpClient build() {
return new OkHttpClient(this)
}
- OkHttpClient.newCall
@Override public Call newCall(Request request) {
return RealCall.newRealCall(this, request, false );
}
static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
RealCall call = new RealCall(client, originalRequest, forWebSocket);
call.transmitter = new Transmitter(client, call);
return call;
}
private RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
this.client = client;
this.originalRequest = originalRequest;
this.forWebSocket = forWebSocket;
}
Call
- Call.execute同步请求方法源码
@Override public Response execute() throws IOException {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
transmitter.timeoutEnter();
transmitter.callStart();
try {
client.dispatcher().executed(this);
return getResponseWithInterceptorChain();
} finally {
client.dispatcher().finished(this);
}
}
- Call.enqueue 异步请求方法源码
@Override public void enqueue(Callback responseCallback) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
transmitter.callStart();
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
Dispatcher任务调度
private int maxRequests = 64;
private int maxRequestsPerHost = 5;
private ExecutorService executorService;
private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();
private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();
private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();
synchronized void executed(RealCall call) {
runningSyncCalls.add(call);
}
- dispatcher().finished用于回收同步请求,实现如下:
void finished(RealCall call) {
finished(runningSyncCalls, call);
}
private <T> void finished(Deque<T> calls, T call) {
Runnable idleCallback;
synchronized (this) {
if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
idleCallback = this.idleCallback;
}
boolean isRunning = promoteAndExecute();
if (!isRunning && idleCallback != null) {
idleCallback.run();
}
}
void enqueue(AsyncCall call) {
synchronized (this) {
readyAsyncCalls.add(call);
if (!call.get().forWebSocket) {
AsyncCall existingCall = findExistingCallWithHost(call.host());
if (existingCall != null) call.reuseCallsPerHostFrom(existingCall);
}
}
promoteAndExecute();
}
- 其入参AsyncCall是RealCall的内部类,构造函数入参就是我们传入的callback,并在execute方法中调用callback,而在NamedRunnable的run中调用了execute方法
final class AsyncCall extends NamedRunnable {
...
void executeOn(ExecutorService executorService) {
assert (!Thread.holdsLock(client.dispatcher()));
boolean success = false;
try {
executorService.execute(this);
success = true;
} catch (RejectedExecutionException e) {
InterruptedIOException ioException = new InterruptedIOException("executor rejected");
ioException.initCause(e);
transmitter.noMoreExchanges(ioException);
responseCallback.onFailure(RealCall.this, ioException);
} finally {
if (!success) {
client.dispatcher().finished(this);
}
}
}
@Override protected void execute() {
boolean signalledCallback = false;
transmitter.timeoutEnter();
try {
Response response = getResponseWithInterceptorChain();
signalledCallback = true;
responseCallback.onResponse(RealCall.this, response);
} catch (IOException e) {
if (signalledCallback) {
Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e);
} else {
responseCallback.onFailure(RealCall.this, e);
}
} catch (Throwable t) {
cancel();
if (!signalledCallback) {
IOException canceledException = new IOException("canceled due to " + t);
canceledException.addSuppressed(t);
responseCallback.onFailure(RealCall.this, canceledException);
}
throw t;
} finally {
client.dispatcher().finished(this);
}
}
}
public abstract class NamedRunnable implements Runnable {
protected final String name;
public NamedRunnable(String format, Object... args) {
this.name = Util.format(format, args);
}
@Override public final void run() {
String oldName = Thread.currentThread().getName();
Thread.currentThread().setName(name);
try {
execute();
} finally {
Thread.currentThread().setName(oldName);
}
}
protected abstract void execute();
}
- 上面AsyncCall的execute中,在最后的finally中也调用了finished用于回收异步请求
void finished(AsyncCall call) {
call.callsPerHost().decrementAndGet();
finished(runningAsyncCalls, call);
}
- finished和异步中都调用了promoteAndExecute方法,其实现如下
private boolean promoteAndExecute() {
assert (!Thread.holdsLock(this));
List<AsyncCall> executableCalls = new ArrayList<>();
boolean isRunning;
synchronized (this) {
for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
AsyncCall asyncCall = i.next();
if (runningAsyncCalls.size() >= maxRequests) break;
if (asyncCall.callsPerHost().get() >= maxRequestsPerHost) continue;
i.remove();
asyncCall.callsPerHost().incrementAndGet();
executableCalls.add(asyncCall);
runningAsyncCalls.add(asyncCall);
}
isRunning = runningCallsCount() > 0;
}
for (int i = 0, size = executableCalls.size(); i < size; i++) {
AsyncCall asyncCall = executableCalls.get(i);
asyncCall.executeOn(executorService());
}
return isRunning;
}
public synchronized ExecutorService executorService() {
if (executorService == null) {
executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
new SynchronousQueue<>(), Util.threadFactory("OkHttp Dispatcher", false));
}
return executorService;
}
public synchronized int runningCallsCount() {
return runningAsyncCalls.size() + runningSyncCalls.size();
}
异步请求的调用顺序:
- 使用者调用Call.enqueue(Callback);
- Call.enqueue中调用了client.dispatcher().enqueue(new AsyncCall(responseCallback));
- dispatcher().enqueue调用promoteAndExecute;
- promoteAndExecute中会遍历readyAsyncCalls,放到executableCalls和runningAsyncCalls中,并调用runningCallsCount重新计算待执行的同步异步请求数量,然后遍历executableCalls,调用 asyncCall.executeOn(executorService());
- asyncCall.executeOn中调用executorService.execute(this),其中this为runnable类型的asyncCall,最后会调用其run方法;
- NamedRunnable的run方法中调用了execute方法,asyncCall中实现了execute方法;
- asyncCall.execute中调用了 Response response = getResponseWithInterceptorChain(),并调用callback,最终调用dispatcher().finished;
- dispatcher().finished中又调用了promoteAndExecute方法,直到队列中的请求都执行完毕;
拦截器链
- 拦截器是okhttp中一个强大的机制,可以实现网络监听,请求及响应重写,请求失败重试等功能;
- 上面的同步请求异步请求源码中都有调用getResponseWithInterceptorChain方法,其代码如下
Response getResponseWithInterceptorChain() throws IOException {
List<Interceptor> interceptors = new ArrayList<>();
interceptors.addAll(client.interceptors());
interceptors.add(new RetryAndFollowUpInterceptor(client));
interceptors.add(new BridgeInterceptor(client.cookieJar()));
interceptors.add(new CacheInterceptor(client.internalCache()));
interceptors.add(new ConnectInterceptor(client));
if (!forWebSocket) {
interceptors.addAll(client.networkInterceptors());
}
interceptors.add(new CallServerInterceptor(forWebSocket));
Interceptor.Chain chain = new RealInterceptorChain(interceptors, transmitter, null, 0,
originalRequest, this, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis());
boolean calledNoMoreExchanges = false;
try {
Response response = chain.proceed(originalRequest);
if (transmitter.isCanceled()) {
closeQuietly(response);
throw new IOException("Canceled");
}
return response;
} catch (IOException e) {
calledNoMoreExchanges = true;
throw transmitter.noMoreExchanges(e);
} finally {
if (!calledNoMoreExchanges) {
transmitter.noMoreExchanges(null);
}
}
}
- 上方法创建一系列拦截器,并放入list中,再创建拦截器链RealInterceptorChain,并执行chain.proceed方法
- proceed方法实现如下:
@Override public Response proceed(Request request) throws IOException {
return proceed(request, transmitter, exchange);
}
public Response proceed(Request request, Transmitter transmitter, @Nullable Exchange exchange)
throws IOException {
...
// Call the next interceptor in the chain.
RealInterceptorChain next = new RealInterceptorChain(interceptors, transmitter, exchange,
index + 1, request, call, connectTimeout, readTimeout, writeTimeout);
Interceptor interceptor = interceptors.get(index);
Response response = interceptor.intercept(next);
...
return response;
}
- 其核心代码九心上面几行,创建下一个拦截器链,调用interceptors.get(index)取得当前拦截器,并执行interceptor.intercept方法得到response返回;
- getResponseWithInterceptorChain中传入的index为0,则当前拦截器就是RetryAndFollowUpInterceptor,那么我们来看看他的intercept方法是如何实现的
RetryAndFollowUpInterceptor
- RetryAndFollowUpInterceptor的intercept方法代码如下
@Override public Response intercept(Chain chain) throws IOException {
Request request = chain.request()
//还记得interceptor.intercept(next)么,所以这里的realChain是下一个拦截器链
RealInterceptorChain realChain = (RealInterceptorChain) chain
Transmitter transmitter = realChain.transmitter()
int followUpCount = 0
Response priorResponse = null
while (true) {
transmitter.prepareToConnect(request)
if (transmitter.isCanceled()) {
throw new IOException("Canceled")
}
Response response
boolean success = false
try {
//调用下一个拦截器链的proceed方法
response = realChain.proceed(request, transmitter, null)
success = true
} catch (RouteException e) {
// The attempt to connect via a route failed. The request will not have been sent.
if (!recover(e.getLastConnectException(), transmitter, false, request)) {
throw e.getFirstConnectException()
}
continue
//当发生IOException或者RouteException时会执行recover方法
} catch (IOException e) {
// An attempt to communicate with a server failed. The request may have been sent.
boolean requestSendStarted = !(e instanceof ConnectionShutdownException)
if (!recover(e, transmitter, requestSendStarted, request)) throw e
continue
} finally {
// The network call threw an exception. Release any resources.
if (!success) {
transmitter.exchangeDoneDueToException()
}
}
// Attach the prior response if it exists. Such responses never have a body.
if (priorResponse != null) {
response = response.newBuilder()
.priorResponse(priorResponse.newBuilder()
.body(null)
.build())
.build()
}
Exchange exchange = Internal.instance.exchange(response)
Route route = exchange != null ? exchange.connection().route() : null
Request followUp = followUpRequest(response, route)
if (followUp == null) {
if (exchange != null && exchange.isDuplex()) {
transmitter.timeoutEarlyExit()
}
return response
}
RequestBody followUpBody = followUp.body()
if (followUpBody != null && followUpBody.isOneShot()) {
return response
}
closeQuietly(response.body())
if (transmitter.hasExchange()) {
exchange.detachWithViolence()
}
//重试次数判断
if (++followUpCount > MAX_FOLLOW_UPS) {
throw new ProtocolException("Too many follow-up requests: " + followUpCount)
}
request = followUp
priorResponse = response
}
}
private boolean recover(IOException e, Transmitter transmitter,
boolean requestSendStarted, Request userRequest) {
if (!client.retryOnConnectionFailure()) return false;
if (requestSendStarted && requestIsOneShot(e, userRequest)) return false;
if (!isRecoverable(e, requestSendStarted)) return false;
if (!transmitter.canRetry()) return false;
return true;
}
- RetryAndFollowUpInterceptor的intercept方法中调用下一个拦截器链的proceed方法获取response,
并在while (true) 循环中根据异常结果或响应结果判断是否要进行重新请求,如当发生IOException或者RouteException时会执行recover方法,
并且通过++followUpCount > MAX_FOLLOW_UPS判断最大重试次数,超出则直接跳出循环;
- 由RealInterceptorChain.proceed可知会继续调用下一个拦截器的intercept方法,由getResponseWithInterceptorChain中顺序可知下一个拦截器就是BridgeInterceptor
- 那么来继续看一下BridgeInterceptor的intercept方法
BridgeInterceptor
- BridgeInterceptor的intercept方法如下
@Override public Response intercept(Chain chain) throws IOException {
Request userRequest = chain.request();
Request.Builder requestBuilder = userRequest.newBuilder();
RequestBody body = userRequest.body();
if (body != null) {
MediaType contentType = body.contentType();
if (contentType != null) {
requestBuilder.header("Content-Type", contentType.toString());
}
long contentLength = body.contentLength();
if (contentLength != -1) {
requestBuilder.header("Content-Length", Long.toString(contentLength));
requestBuilder.removeHeader("Transfer-Encoding");
} else {
requestBuilder.header("Transfer-Encoding", "chunked");
requestBuilder.removeHeader("Content-Length");
}
}
if (userRequest.header("Host") == null) {
requestBuilder.header("Host", hostHeader(userRequest.url(), false));
}
if (userRequest.header("Connection") == null) {
requestBuilder.header("Connection", "Keep-Alive");
}
boolean transparentGzip = false;
if (userRequest.header("Accept-Encoding") == null && userRequest.header("Range") == null) {
transparentGzip = true;
requestBuilder.header("Accept-Encoding", "gzip");
}
List<Cookie> cookies = cookieJar.loadForRequest(userRequest.url());
if (!cookies.isEmpty()) {
requestBuilder.header("Cookie", cookieHeader(cookies));
}
if (userRequest.header("User-Agent") == null) {
requestBuilder.header("User-Agent", Version.userAgent());
}
Response networkResponse = chain.proceed(requestBuilder.build());
HttpHeaders.receiveHeaders(cookieJar, userRequest.url(), networkResponse.headers());
Response.Builder responseBuilder = networkResponse.newBuilder()
.request(userRequest);
if (transparentGzip
&& "gzip".equalsIgnoreCase(networkResponse.header("Content-Encoding"))
&& HttpHeaders.hasBody(networkResponse)) {
GzipSource responseBody = new GzipSource(networkResponse.body().source());
Headers strippedHeaders = networkResponse.headers().newBuilder()
.removeAll("Content-Encoding")
.removeAll("Content-Length")
.build();
responseBuilder.headers(strippedHeaders);
String contentType = networkResponse.header("Content-Type");
responseBuilder.body(new RealResponseBody(contentType, -1L, Okio.buffer(responseBody)));
}
return responseBuilder.build();
}
- BridgeInterceptor的intercept中,先各种判断对RequestBody的请求头进行补充,将其转化为能够进行网络访问的请求,然后调用下一个拦截器链的proceed方法获取response,再对respone的响应头进行补充,如设置cookieJar,gzip解压,将请求回来的响应response转化为用户可用的response;
- 调用下一个拦截器链的proceed,又会调用下一个拦截器的intercept方法,下一个拦截器为CacheInterceptor
CacheInterceptor
- CacheInterceptor的intercept方法如下
@Override public Response intercept(Chain chain) throws IOException {
Response cacheCandidate = cache != null
? cache.get(chain.request())
: null;
long now = System.currentTimeMillis();
CacheStrategy strategy = new CacheStrategy.Factory(now, chain.request(), cacheCandidate).get();
Request networkRequest = strategy.networkRequest;
Response cacheResponse = strategy.cacheResponse;
if (cache != null) {
cache.trackResponse(strategy);
}
if (cacheCandidate != null && cacheResponse == null) {
closeQuietly(cacheCandidate.body());
}
if (networkRequest == null && cacheResponse == null) {
return new Response.Builder()
.request(chain.request())
.protocol(Protocol.HTTP_1_1)
.code(504)
.message("Unsatisfiable Request (only-if-cached)")
.body(Util.EMPTY_RESPONSE)
.sentRequestAtMillis(-1L)
.receivedResponseAtMillis(System.currentTimeMillis())
.build();
}
if (networkRequest == null) {
return cacheResponse.newBuilder()
.cacheResponse(stripBody(cacheResponse))
.build();
}
Response networkResponse = null;
try {
networkResponse = chain.proceed(networkRequest);
} finally {
if (networkResponse == null && cacheCandidate != null) {
closeQuietly(cacheCandidate.body());
}
}
if (cacheResponse != null) {
if (networkResponse.code() == HTTP_NOT_MODIFIED) {
Response 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;
} else {
closeQuietly(cacheResponse.body());
}
}
Response response = networkResponse.newBuilder()
.cacheResponse(stripBody(cacheResponse))
.networkResponse(stripBody(networkResponse))
.build();
if (cache != null) {
if (HttpHeaders.hasBody(response) && CacheStrategy.isCacheable(response, networkRequest)) {
CacheRequest cacheRequest = cache.put(response);
return cacheWritingResponse(cacheRequest, response);
}
if (HttpMethod.invalidatesCache(networkRequest.method())) {
try {
cache.remove(networkRequest);
} catch (IOException ignored) {
}
}
}
return response;
}
- CacheInterceptor的intercept中对用不用缓存和对缓存是否更新进行了各种判断,如果用网络请求也会调用下一个拦截器链的proceed方法获取response,
- 那么下一个拦截器就是ConnectInterceptor
ConnectInterceptor
- ConnectInterceptor的intercept方法如下, 正式开启okhttp的网络请求
@Override public Response intercept(Chain chain) throws IOException {
RealInterceptorChain realChain = (RealInterceptorChain) chain
Request request = realChain.request()
Transmitter transmitter = realChain.transmitter()
// We need the network to satisfy this request. Possibly for validating a conditional GET.
boolean doExtensiveHealthChecks = !request.method().equals("GET")
Exchange exchange = transmitter.newExchange(chain, doExtensiveHealthChecks)
return realChain.proceed(request, transmitter, exchange)
}
- 上面调用transmitter.newExchange获取Exchange,并调用下一个拦截器链的proceed传给下一个拦截器,获取response,newExchange方法如下
Exchange newExchange(Interceptor.Chain chain, boolean doExtensiveHealthChecks) {
...
ExchangeCodec codec = exchangeFinder.find(client, chain, doExtensiveHealthChecks)
Exchange result = new Exchange(this, call, eventListener, exchangeFinder, codec)
...
}
- 上面调用了exchangeFinder.find获取ExchangeCodec, 其中通过findHealthyConnection得到RealConnection,再return RealConnection.newCode
public ExchangeCodec find(OkHttpClient client, Interceptor.Chain chain, boolean doExtensiveHealthChecks) {
...
RealConnection resultConnection = findHealthyConnection(connectTimeout, readTimeout,
writeTimeout, pingIntervalMillis, connectionRetryEnabled, doExtensiveHealthChecks);
return resultConnection.newCodec(client, chain);
...
}
- findHealthyConnection又调用了findConnection方法, findConnection方法代码如下, 其中通过连接池或 new RealConnection获取RealConnection,并调用了其connect方法
- 源码很长,下面只是列出了关键步骤
private RealConnection findConnection(int connectTimeout, int readTimeout, int writeTimeout,
int pingIntervalMillis, boolean connectionRetryEnabled) throws IOException {
boolean foundPooledConnection = false;
RealConnection result = null;
...
if (result == null) {
if (connectionPool.transmitterAcquirePooledConnection(address, transmitter, null, false)) {
foundPooledConnection = true;
result = transmitter.connection;
}
...
}
...
if (result != null) {
return result;
}
...
result = new RealConnection(connectionPool, selectedRoute);
result.connect(connectTimeout, readTimeout, writeTimeout, pingIntervalMillis,
connectionRetryEnabled, call, eventListener);
connectionPool.routeDatabase.connected(result.route());
...
return result;
}
CallServerInterceptor
- 最后来看看CallServerInterceptor的intercept
@Override public Response intercept(Chain chain) throws IOException {
RealInterceptorChain realChain = (RealInterceptorChain) chain;
Exchange exchange = realChain.exchange();
Request request = realChain.request();
long sentRequestMillis = System.currentTimeMillis();
exchange.writeRequestHeaders(request);
boolean responseHeadersStarted = false;
Response.Builder responseBuilder = null;
if (HttpMethod.permitsRequestBody(request.method()) && request.body() != null) {
if ("100-continue".equalsIgnoreCase(request.header("Expect"))) {
exchange.flushRequest();
responseHeadersStarted = true;
exchange.responseHeadersStart();
responseBuilder = exchange.readResponseHeaders(true);
}
if (responseBuilder == null) {
if (request.body().isDuplex()) {
exchange.flushRequest();
BufferedSink bufferedRequestBody = Okio.buffer(
exchange.createRequestBody(request, true));
request.body().writeTo(bufferedRequestBody);
} else {
BufferedSink bufferedRequestBody = Okio.buffer(
exchange.createRequestBody(request, false));
request.body().writeTo(bufferedRequestBody);
bufferedRequestBody.close();
}
} else {
exchange.noRequestBody();
if (!exchange.connection().isMultiplexed()) {
exchange.noNewExchangesOnConnection();
}
}
} else {
exchange.noRequestBody();
}
if (request.body() == null || !request.body().isDuplex()) {
exchange.finishRequest();
}
if (!responseHeadersStarted) {
exchange.responseHeadersStart();
}
if (responseBuilder == null) {
responseBuilder = exchange.readResponseHeaders(false);
}
Response response = responseBuilder
.request(request)
.handshake(exchange.connection().handshake())
.sentRequestAtMillis(sentRequestMillis)
.receivedResponseAtMillis(System.currentTimeMillis())
.build();
int code = response.code();
if (code == 100) {
response = exchange.readResponseHeaders(false)
.request(request)
.handshake(exchange.connection().handshake())
.sentRequestAtMillis(sentRequestMillis)
.receivedResponseAtMillis(System.currentTimeMillis())
.build();
code = response.code();
}
exchange.responseHeadersEnd(response);
if (forWebSocket && code == 101) {
response = response.newBuilder()
.body(Util.EMPTY_RESPONSE)
.build();
} else {
response = response.newBuilder()
.body(exchange.openResponseBody(response))
.build();
}
if ("close".equalsIgnoreCase(response.request().header("Connection"))
|| "close".equalsIgnoreCase(response.header("Connection"))) {
exchange.noNewExchangesOnConnection();
}
if ((code == 204 || code == 205) && response.body().contentLength() > 0) {
throw new ProtocolException(
"HTTP " + code + " had non-zero Content-Length: " + response.body().contentLength());
}
return response;
}
我是今阳,如果想要进阶和了解更多的干货,欢迎关注微信公众号 “今阳说” 接收我的最新文章