以下就是OKHttp的一个普通流程:
boolean isAsync = true;
OkHttpClient cilent = new OkHttpClient.Builder().build();
Call call = cilent.newCall(new Request.Builder().url("").get().build());
try {
if(isAsync){
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
}
});
}else{
Response response = call.execute();
}
} catch (IOException e) {
e.printStackTrace();
}首先初始化OKHttpCilent,直接看Build()方法:
OKHttpCilent:
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);
}初始化okHttp需要用到的一些对象,以及各类超时时间,如果没有指定,就按照这些默认的初始化。
然后构造出okHttpCilent通过newCall构造出Call对象:
OKHttpCilent:
@Override public Call newCall(Request request) {
return RealCall.newRealCall(this, request, false /* for web socket */);
}
RealCall:
static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
// Safely publish the Call instance to the EventListener.
RealCall call = new RealCall(client, originalRequest, forWebSocket);
call.eventListener = client.eventListenerFactory().create(call);
return call;
}private RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
this.client = client;
this.originalRequest = originalRequest;
this.forWebSocket = forWebSocket;
this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);
//超时,工具调用超时跨越整个调用:解析DNS,连接,写请求,主体,服务器处理,并读取响应主体。
//如果调用需要重定向或所有重试必须在一个超时时间内完成,否则到时间就会调用cancel方法。
//默认为0,不超时
this.timeout = new AsyncTimeout() {
@Override protected void timedOut() {
cancel();
}
};
this.timeout.timeout(client.callTimeoutMillis(), MILLISECONDS);
}realCall构造方法三个参数,分别是OkHttpCilent对象,Request对象以及是否websocket请求,这里普通请求为false。(如果使用cilent.newWebSocket方法后面后会构造RealCall对象,并且forWebSocket会传入true)。同时这里会创建call的回调eventListener:
EventListener:
public static final EventListener NONE = new EventListener() {
};
static EventListener.Factory factory(final EventListener listener) {
return new EventListener.Factory() {
public EventListener create(Call call) {
return listener;
}
};
}上面OkHttpCilent.Build()默认传入的就是NONE对象,用户可自己指定实现,主要call的各类执行过程回调。
RealCall对象创造好后,就可以执行请求方法了,可以同步也可以异步,先看同步方法:
RealCall:
@Override public Response execute() throws IOException {
//标记已经执行,防止重复执行
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
//超时开始计算
timeout.enter();
eventListener.callStart(this);
try {
//将call对象加入到Dispatcher的runningSyncCalls(同步队列)中
//Dispatcher对象已经在OkHttpClient.Build()中创建了
client.dispatcher().executed(this);
//开始责任链执行请求
Response result = getResponseWithInterceptorChain();
if (result == null) throw new IOException("Canceled");
return result;
} catch (IOException e) {
e = timeoutExit(e);
eventListener.callFailed(this, e);
throw e;
} finally {
//结束该call,分析见下面异步finish方法
client.dispatcher().finished(this);
}
}Dispatcher:
synchronized void executed(RealCall call) {
runningSyncCalls.add(call);
}异步请求方法:
RealCall:
@Override public void enqueue(Callback responseCallback) {
//标记已经执行,防止重复执行
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
eventListener.callStart(this);
//将realCall包装成AsynCall(线程),放入Dispatcher中的readyAsyncCalls中(异步等待队列)
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}Dispatcher:
void enqueue(AsyncCall call) {
synchronized (this) {
readyAsyncCalls.add(call);
}
promoteAndExecute();
}
//循环遍历等待异步队列,取出可执行的异步call
private boolean promoteAndExecute() {
assert (!Thread.holdsLock(this));
//存放从等待队列中取出的可以执行的异步call
List<AsyncCall> executableCalls = new ArrayList<>();
boolean isRunning;
synchronized (this) {
//如果runningAsyncCalls(异步运行队列)长度小于64且指向同一host的运行异步call小于5,
//则取出异步call放入executableCalls和runningAsyncCalls(异步运行队列)中,
//从readyAsyncCalls中移除该异步Call
for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
AsyncCall asyncCall = i.next();
if (runningAsyncCalls.size() >= maxRequests) break; // Max capacity.
if (runningCallsForHost(asyncCall) >= maxRequestsPerHost) continue; // Host max capacity.
i.remove();
executableCalls.add(asyncCall);
runningAsyncCalls.add(asyncCall);
}
//如果不为空,说明还有需要执行的异步call
isRunning = runningCallsCount() > 0;
}
//再一次循环,取出所有可以执行的异步call,放入线程池(executorService)中执行
for (int i = 0, size = executableCalls.size(); i < size; i++) {
AsyncCall asyncCall = executableCalls.get(i);
asyncCall.executeOn(executorService());
}
return isRunning;
}Dispatcher:
//这是一个没有核心线程,以及无限大非核心线程,超时时间为60秒的线程池
public synchronized ExecutorService executorService() {
if (executorService == null) {
executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false));
}
return executorService;
}asyncCall的executeOn方法:
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);
eventListener.callFailed(RealCall.this, ioException);
responseCallback.onFailure(RealCall.this, ioException);
} finally {
if (!success) {
//这边会移除call然后寻找下一个可执行的
client.dispatcher().finished(this); // This call is no longer running!
}
}
}Dispatcher:
//异步call执行的finish方法
void finished(AsyncCall call) {
finished(runningAsyncCalls, call);
}
//同步call执行的finish方法
void finished(RealCall call) {
finished(runningSyncCalls, call);
}
//从对应队列中移除该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();
//如果没有可运行的异步call且idleCallback不为空(idleCallback自己设置),执行idleCallback run方法
if (!isRunning && idleCallback != null) {
idleCallback.run();
}
}上面已经把异步同步请求以及结束的一些细节讲完了,接下来就是最重要的请求流程了。
RealCall:
Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
List<Interceptor> interceptors = new ArrayList<>();
interceptors.addAll(client.interceptors());
interceptors.add(retryAndFollowUpInterceptor);
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, null, null, null, 0,
originalRequest, this, eventListener, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis());
Response response = chain.proceed(originalRequest);
if (retryAndFollowUpInterceptor.isCanceled()) {
closeQuietly(response);
throw new IOException("Canceled");
}
return response;
}这里先将用户设置的应用拦截器全部加入,然后再加入其它拦截器,再最后一个拦截器之前再加入用户设置的网络拦截器,这样的话应用拦截器即使在发生重定向时也只会执行一次,而网络拦截器就会多次执行了。构建出RealInterceptorChain对象,执行了proceed方法,请求就正式开始了。
RealInterceptorChain:
public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
RealConnection connection) throws IOException {
//index每次回来一次都会加1,如果大于等于拦截器,说明执行过多出错
if (index >= interceptors.size()) throw new AssertionError();
calls++;
// If we already have a stream, confirm that the incoming request will use it.
if (this.httpCodec != null && !this.connection.supportsUrl(request.url())) {
throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
+ " must retain the same host and port");
}
// If we already have a stream, confirm that this is the only call to chain.proceed().
if (this.httpCodec != null && calls > 1) {
throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
+ " must call proceed() exactly once");
}
//每次使用chain.process(request)方法就会回来这里,然后创建新的RealInterceptorChain对象,同时
//index会递增加1,这样每次都会获取到数组中下一个拦截器,然后执行拦截器的intercept方法,同时还会
//将新构建的RealInterceptorChain传进去
RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
writeTimeout);
Interceptor interceptor = interceptors.get(index);
Response response = interceptor.intercept(next);
// Confirm that the next interceptor made its required call to chain.proceed().
if (httpCodec != null && index + 1 < interceptors.size() && next.calls != 1) {
throw new IllegalStateException("network interceptor " + interceptor
+ " must call proceed() exactly once");
}
// Confirm that the intercepted response isn't null.
if (response == null) {
throw new NullPointerException("interceptor " + interceptor + " returned null");
}
if (response.body() == null) {
throw new IllegalStateException(
"interceptor " + interceptor + " returned a response with no body");
}
return response;
}先看retryAndFollowUpInterceptor,这也是系统设置的第一个拦截器:
retryAndFollowUpInterceptor:
@Override public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
RealInterceptorChain realChain = (RealInterceptorChain) chain;
Call call = realChain.call();
EventListener eventListener = realChain.eventListener();
//用来管理connections、stream、routerSelector的类
StreamAllocation streamAllocation = new StreamAllocation(client.connectionPool(),
createAddress(request.url()), call, eventListener, callStackTrace);
this.streamAllocation = streamAllocation;
//重定向次数
int followUpCount = 0;
//如果发生重定向,记录上次的response
Response priorResponse = null;
//循环获取请求结果
while (true) {
//如果取消了,则释放流
if (canceled) {
streamAllocation.release();
throw new IOException("Canceled");
}
Response response;
boolean releaseConnection = true;
try {
//会回到realChainInterceptor的proceed方法,传递过去stremAllocation,
//构建新realChain,执行下一个拦截器
response = realChain.proceed(request, streamAllocation, null, null);
releaseConnection = false;
} catch (RouteException e) {
// The attempt to connect via a route failed. The request will not have been sent.
if (!recover(e.getLastConnectException(), streamAllocation, false, request)) {
throw e.getFirstConnectException();
}
releaseConnection = false;
continue;
} 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, streamAllocation, requestSendStarted, request)) throw e;
releaseConnection = false;
continue;
} finally {
// We're throwing an unchecked exception. Release any resources.
if (releaseConnection) {
streamAllocation.streamFailed(null);
streamAllocation.release();
}
}
// 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();
}
//这里是获取重定向请求
Request followUp;
try {
//如果是407代理认证则执行client.proxyAuthenticator().authenticate(router,userResponse)方法
//如果是401身份认证则执行client.authenticator().authenticate(route, userResponse)
//OkHttpClient默认初始化为Authenticator.NONE
//如果是其他一些3xx的则获取location网址,重新包装request请求等等,不支持则返回null
followUp = followUpRequest(response, streamAllocation.route());
} catch (IOException e) {
streamAllocation.release();
throw e;
}
//重定向请求不支持或不需要,释放流,返回response,请求结束
if (followUp == null) {
streamAllocation.release();
return response;
}
closeQuietly(response.body());
//如果重定向次数超过20,则释放流,并抛出异常
if (++followUpCount > MAX_FOLLOW_UPS) {
streamAllocation.release();
throw new ProtocolException("Too many follow-up requests: " + followUpCount);
}
if (followUp.body() instanceof UnrepeatableRequestBody) {
streamAllocation.release();
throw new HttpRetryException("Cannot retry streamed HTTP body", response.code());
}
//判断重定向请求和前一个请求是否是同一个主机,如果不是重新创建连接
if (!sameConnection(response, followUp.url())) {
streamAllocation.release();
streamAllocation = new StreamAllocation(client.connectionPool(),
createAddress(followUp.url()), call, eventListener, callStackTrace);
this.streamAllocation = streamAllocation;
} else if (streamAllocation.codec() != null) {
throw new IllegalStateException("Closing the body of " + response
+ " didn't close its backing stream. Bad interceptor?");
}
request = followUp;
priorResponse = response;
}
}第二个拦截器,也是最简单的拦截器了,BridgeInterceptor:
BridgeInterceptor:
@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());
}
//能确定contentLendth,就移除Transfer-Encoding(代表不确定内容长度),否则反过来
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));
}
//http1.1开始默认开启Keep-Alive
if (userRequest.header("Connection") == null) {
requestBuilder.header("Connection", "Keep-Alive");
}
//如果没指定编码方式以及请求范围,则添加gzip方式
boolean transparentGzip = false;
if (userRequest.header("Accept-Encoding") == null && userRequest.header("Range") == null) {
transparentGzip = true;
requestBuilder.header("Accept-Encoding", "gzip");
}
//看是否有cookie信息,默认设置为OkHttpClient设置的NO_COOKIES
List<Cookie> cookies = cookieJar.loadForRequest(userRequest.url());
if (!cookies.isEmpty()) {
requestBuilder.header("Cookie", cookieHeader(cookies));
}
//添加版本信息,这里默认写死的“okhttp/3.12.3”(跟okHttp版本相关)
if (userRequest.header("User-Agent") == null) {
requestBuilder.header("User-Agent", Version.userAgent());
}
//责任链继续执行下一个拦截器
Response networkResponse = chain.proceed(requestBuilder.build());
//保存cookie信息
HttpHeaders.receiveHeaders(cookieJar, userRequest.url(), networkResponse.headers());
Response.Builder responseBuilder = networkResponse.newBuilder()
.request(userRequest);
//判断服务器是否支持gzip压缩,如果支持,则将压缩提交给Okio库来处理
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();
}下一个拦截器就是CacheIntercepter,听上去就知道是缓存拦截器了,这里的cache也是需要初始化OkHttpClient时候传入,默认为空,缓存策略详细可看这里blog.csdn.net/qq_30993595…
CacheIntercepter:
@Override public Response intercept(Chain chain) throws IOException {
//获取缓存的response
Response cacheCandidate = cache != null
? cache.get(chain.request())
: null;
long now = System.currentTimeMillis();
//这边会去解析cacheCandidate(如果不为空)和request的请求头,获取请求缓存的规则
CacheStrategy strategy = new CacheStrategy.Factory(now, chain.request(), cacheCandidate).get();
//networkRequest为null则不用网络
Request networkRequest = strategy.networkRequest;
//cacheResponse为null则不用缓存
Response cacheResponse = strategy.cacheResponse;
//更新缓存策略
if (cache != null) {
cache.trackResponse(strategy);
}
//获取到本地缓存但是不用缓存,关闭缓存
if (cacheCandidate != null && cacheResponse == null) {
closeQuietly(cacheCandidate.body()); // The cache candidate wasn't applicable. Close it.
}
//不用网络也不用缓存,也就是本地无缓存且请求头有only-if-cached信息,返回504错误
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 we're crashing on I/O or otherwise, don't leak the cache body.
if (networkResponse == null && cacheCandidate != null) {
closeQuietly(cacheCandidate.body());
}
}
//可以使用缓存且后台返回304,表明可以继续使用原先缓存,合并缓存和响应,更新缓存
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();
// Update the cache after combining headers but before stripping the
// Content-Encoding header (as performed by initContentStream()).
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) {
//如果响应有响应体且返回码正常,请求头和响应头都无no-store值,则写入缓存并返回
if (HttpHeaders.hasBody(response) && CacheStrategy.isCacheable(response, networkRequest)) {
// Offer this request to the cache.
CacheRequest cacheRequest = cache.put(response);
return cacheWritingResponse(cacheRequest, response);
}
//移除非法缓存,例如post,put一类方法的
if (HttpMethod.invalidatesCache(networkRequest.method())) {
try {
cache.remove(networkRequest);
} catch (IOException ignored) {
// The cache cannot be written.
}
}
}
return response;
}接下来就是ConnectInterceptor拦截器,连接服务器,这里用到了在RetryAndFollowUpInterceptor拦截器中创建的StreamAllocation对象了:
ConnectInterceptor:
@Override public Response intercept(Chain chain) throws IOException {
RealInterceptorChain realChain = (RealInterceptorChain) chain;
Request request = realChain.request();
StreamAllocation streamAllocation = realChain.streamAllocation();
boolean doExtensiveHealthChecks = !request.method().equals("GET");
//用来编码HTTP请求和解码HTTP响应
HttpCodec httpCodec = streamAllocation.newStream(client, chain, doExtensiveHealthChecks);
//里面保存了一个Socket负责连接,Handshake负责握手,
//List<Reference< StreamAllocation>> allocations负责保存开辟的stream
RealConnection connection = streamAllocation.connection();
return realChain.proceed(request, streamAllocation, httpCodec, connection);
}代码如上,连接操作由streamAllocation来完成,接下来就是比较复杂的代码了:
StreamAllocation:
public HttpCodec newStream(
OkHttpClient client, Interceptor.Chain chain, boolean doExtensiveHealthChecks) {
//连接超时,默认10秒
int connectTimeout = chain.connectTimeoutMillis();
//读取超时,默认10秒
int readTimeout = chain.readTimeoutMillis();
//写入超时,默认10秒
int writeTimeout = chain.writeTimeoutMillis();
//Websocket ping 间隔 (毫秒) 定时通知服务器,为心跳连接做准备,默认为0,不执行心跳
int pingIntervalMillis = client.pingIntervalMillis();
//失败重连,默认true
boolean connectionRetryEnabled = client.retryOnConnectionFailure();
try {
//寻找连接
RealConnection resultConnection = findHealthyConnection(connectTimeout, readTimeout,
writeTimeout, pingIntervalMillis, connectionRetryEnabled, doExtensiveHealthChecks);
HttpCodec resultCodec = resultConnection.newCodec(client, chain, this);
synchronized (connectionPool) {
codec = resultCodec;
return resultCodec;
}
} catch (IOException e) {
throw new RouteException(e);
}
}
private RealConnection findHealthyConnection(int connectTimeout, int readTimeout,
int writeTimeout, int pingIntervalMillis, boolean connectionRetryEnabled,
boolean doExtensiveHealthChecks) throws IOException {
//循环寻找连接
while (true) {
RealConnection candidate = findConnection(connectTimeout, readTimeout, writeTimeout,
pingIntervalMillis, connectionRetryEnabled);
//新建的连接的successCount为0,直接返回
synchronized (connectionPool) {
if (candidate.successCount == 0) {
return candidate;
}
}
//如果被关闭了,则释放连接
if (!candidate.isHealthy(doExtensiveHealthChecks)) {
noNewStreams();
continue;
}
return candidate;
}
}上面代码都知识来调用方法查找连接,查找连接的具体如下:
StreamAllocation:
private RealConnection findConnection(int connectTimeout, int readTimeout, int writeTimeout,
int pingIntervalMillis, boolean connectionRetryEnabled) throws IOException {
boolean foundPooledConnection = false;
RealConnection result = null;
Route selectedRoute = null;
Connection releasedConnection;
Socket toClose;
synchronized (connectionPool) {
//判断是否符合条件
if (released) throw new IllegalStateException("released");
if (codec != null) throw new IllegalStateException("codec != null");
if (canceled) throw new IOException("Canceled");
//如果有连接存在,直接复用
releasedConnection = this.connection;
//如果当前连接已经不能分配新的流,就释放资源,并返回当前连接的Socket对象,
//并会把this.connection置为null
toClose = releaseIfNoNewStreams();
if (this.connection != null) {
result = this.connection;
releasedConnection = null;
}
if (!reportedAcquired) {
// If the connection was never reported acquired, don't report it as released!
releasedConnection = null;
}
if (result == null) {
// 这个instance在OkHttpClient中实例化了.
// 实际调用了ConnectionPool中的get(address,steamallocation,route)方法
// 遍历存在的连接,符合条件的取出复用
Internal.instance.get(connectionPool, address, this, null);
if (connection != null) {
foundPooledConnection = true;
result = connection;
} else {
selectedRoute = route;
}
}
}
//关闭当前不能分配流的socket
closeQuietly(toClose);
if (releasedConnection != null) {
eventListener.connectionReleased(call, releasedConnection);
}
if (foundPooledConnection) {
eventListener.connectionAcquired(call, result);
}
if (result != null) {
// If we found an already-allocated or pooled connection, we're done.
route = connection.route();
return result;
}
//上面没有从连接池里找到合适的连接,需要递归创建一个路由,是个阻塞的过程
boolean newRouteSelection = false;
if (selectedRoute == null && (routeSelection == null || !routeSelection.hasNext())) {
newRouteSelection = true;
routeSelection = routeSelector.next();
}
synchronized (connectionPool) {
if (canceled) throw new IOException("Canceled");
if (newRouteSelection) {
// 现在有了ip address,那就更换路由再从连接池里获取 对多IP的支持
List<Route> routes = routeSelection.getAll();
for (int i = 0, size = routes.size(); i < size; i++) {
Route route = routes.get(i);
Internal.instance.get(connectionPool, address, this, route);
if (connection != null) {
foundPooledConnection = true;
result = connection;
this.route = route;
break;
}
}
}
if (!foundPooledConnection) {
if (selectedRoute == null) {
selectedRoute = routeSelection.next();
}
// 到这里说明实在找不到 必须要实例化一个连接了
route = selectedRoute;
refusedStreamCount = 0;
result = new RealConnection(connectionPool, selectedRoute);
//表明要用这个连接
acquire(result, false);
}
// If we found a pooled connection on the 2nd time around, we're done.
if (foundPooledConnection) {
eventListener.connectionAcquired(call, result);
return result;
}
// 对于新创建的连接,要执行TCP + TLS握手来建立连接 阻塞操作(这里会创建socket)
result.connect(connectTimeout, readTimeout, writeTimeout, pingIntervalMillis,
connectionRetryEnabled, call, eventListener);
//移除失败名单
routeDatabase().connected(result.route());
Socket socket = null;
synchronized (connectionPool) {
reportedAcquired = true;
//将连接放入连接池
Internal.instance.put(connectionPool, result);
// If another multiplexed connection to the same address was created concurrently, then
// release this connection and acquire that one.
if (result.isMultiplexed()) {
// 如果当前创建的连接支持多路复用(只要是HTTP/2连接,就可以同时用于多个HTTP请求),
//同时连接池里存在一个同样的连接,那就释放掉当前这个连接,复用连接池里的连接
socket = Internal.instance.deduplicate(connectionPool, address, this);
result = connection;
}
}
closeQuietly(socket);
eventListener.connectionAcquired(call, result);
return result;细节可参考:www.jianshu.com/p/6166d2898…
接下来来到最后一个拦截器,CallServerInterceptor,给服务器发送数据:
CallServerInterceptor:
@Override public Response intercept(Chain chain) throws IOException {
//拿到之前初始好的对象
RealInterceptorChain realChain = (RealInterceptorChain) chain;
HttpCodec httpCodec = realChain.httpStream();
StreamAllocation streamAllocation = realChain.streamAllocation();
RealConnection connection = (RealConnection) realChain.connection();
Request request = realChain.request();
//记录发送时间
long sentRequestMillis = System.currentTimeMillis();
realChain.eventListener().requestHeadersStart(realChain.call());
//往sink里写入请求头
httpCodec.writeRequestHeaders(request);
realChain.eventListener().requestHeadersEnd(realChain.call(), request);
Response.Builder responseBuilder = null;
//如果不是get请求,也就是有请求体
if (HttpMethod.permitsRequestBody(request.method()) && request.body() != null) {
//如果请求头中有"Expect: 100-continue"协议,等待服务器返回100确定是否接收请求体
// 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".equalsIgnoreCase(request.header("Expect"))) {
httpCodec.flushRequest();
realChain.eventListener().responseHeadersStart(realChain.call());
responseBuilder = httpCodec.readResponseHeaders(true);
}
//如果服务器返回100,那responseBuilder为null,说明服务器等待接收请求体,开始写入请求体
if (responseBuilder == null) {
// Write the request body if the "Expect: 100-continue" expectation was met.
realChain.eventListener().requestBodyStart(realChain.call());
long contentLength = request.body().contentLength();
CountingSink requestBodyOut =
new CountingSink(httpCodec.createRequestBody(request, contentLength));
BufferedSink bufferedRequestBody = Okio.buffer(requestBodyOut);
request.body().writeTo(bufferedRequestBody);
bufferedRequestBody.close();
realChain.eventListener()
.requestBodyEnd(realChain.call(), requestBodyOut.successfulCount);
} else if (!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.
streamAllocation.noNewStreams();
}
}
//sink.flush()
httpCodec.finishRequest();
//读取响应头
if (responseBuilder == null) {
realChain.eventListener().responseHeadersStart(realChain.call());
responseBuilder = httpCodec.readResponseHeaders(false);
}
Response response = responseBuilder
.request(request)
.handshake(streamAllocation.connection().handshake())
.sentRequestAtMillis(sentRequestMillis)
.receivedResponseAtMillis(System.currentTimeMillis())
.build();
//读取响应体
int code = response.code();
if (code == 100) {
// server sent a 100-continue even though we did not request one.
// try again to read the actual response
responseBuilder = httpCodec.readResponseHeaders(false);
response = responseBuilder
.request(request)
.handshake(streamAllocation.connection().handshake())
.sentRequestAtMillis(sentRequestMillis)
.receivedResponseAtMillis(System.currentTimeMillis())
.build();
code = response.code();
}
realChain.eventListener()
.responseHeadersEnd(realChain.call(), response);
if (forWebSocket && code == 101) {
// Connection is upgrading, but we need to ensure interceptors see a non-null response body.
response = response.newBuilder()
.body(Util.EMPTY_RESPONSE)
.build();
} else {
response = response.newBuilder()
.body(httpCodec.openResponseBody(response))
.build();
}
if ("close".equalsIgnoreCase(response.request().header("Connection"))
|| "close".equalsIgnoreCase(response.header("Connection"))) {
streamAllocation.noNewStreams();
}
if ((code == 204 || code == 205) && response.body().contentLength() > 0) {
throw new ProtocolException(
"HTTP " + code + " had non-zero Content-Length: " + response.body().contentLength());
}
return response;
}到这里整个请求就结束了,核心类是 RealConnection、ConnectionPool、StreamAllocation
最后是这两张图(别人博客拿的)