大致的使用是这样的:
OkHttpClient client = ...
OkHttpClient clientWith30sTimeout = client.newBuilder()
.readTimeout(30, TimeUnit.SECONDS)
.build();
Response response = clientWith30sTimeout.newCall(request).execute();
OkHttpClient是产生Call的工厂类,而Call是为执行网络请求做准备的一个接口,Call可以被取消,call对象代表一个单独的request/response对。
public interface Call {
Request request();
Response execute() throws IOException;
void enqueue(Callback responseCallback);
void cancel();
boolean isExecuted();
boolean isCanceled();
interface Factory {
Call newCall(Request request);
}
}
一,究竟一个请求/响应通路是怎么的呢?
OkHttpClient类有个SocketFactory的成员,这是产生Socket的抽象工厂类,它有5个重载的抽象方法。
public abstract SocketcreateSocket(InetAddress address, int port, InetAddress localAddress, int localPort)
throws IOException;
其4个参数含义分别是:服务端地址,服务端端口,本机地址,本机端口。这个抽象类有个默认的实现类DefaultSocketFactory,它创建Socket方法的语句:
return new Socket(address, port, clientAddress, clientPort);
OkHttpClient在构造时做了哪些事情呢?
private OkHttpClient(Builder builder) {
this.dispatcher = builder.dispatcher;
this.proxy = builder.proxy;
this.protocols = builder.protocols;
this.connectionSpecs = builder.connectionSpecs;
this.interceptors = Util.immutableList(builder.interceptors); this.networkInterceptors = Util.immutableList(builder.networkInterceptors);
this.proxySelector = builder.proxySelector;
this.cookieJar = builder.cookieJar;
this.cache = builder.cache;
this.internalCache = builder.internalCache;
this.socketFactory = builder.socketFactory;
boolean isTLS = false;
for (ConnectionSpec spec : connectionSpecs) {
isTLS = isTLS || spec.isTls();
}
if (builder.sslSocketFactory != null || !isTLS) {
this.sslSocketFactory = builder.sslSocketFactory;
this.certificateChainCleaner = builder.certificateChainCleaner;
} else {
X509TrustManager trustManager = systemDefaultTrustManager();
this.sslSocketFactory = systemDefaultSslSocketFactory(trustManager);
this.certificateChainCleaner = CertificateChainCleaner.get(trustManager);
}
this.hostnameVerifier = builder.hostnameVerifier;
this.certificatePinner = builder.certificatePinner.withCertificateChainCleaner( certificateChainCleaner);
this.proxyAuthenticator = builder.proxyAuthenticator;
this.authenticator = builder.authenticator;
this.connectionPool = builder.connectionPool;
this.dns = builder.dns;
this.followSslRedirects = builder.followSslRedirects;
this.followRedirects = builder.followRedirects;
this.retryOnConnectionFailure = builder.retryOnConnectionFailure;
this.connectTimeout = builder.connectTimeout;
this.readTimeout = builder.readTimeout;
this.writeTimeout = builder.writeTimeout;
}
包括代理,协议,拦截器,缓存,socket,连接池,dns,超时,重试等一些请求的准备工作。这里面每一项具体如何发挥作用的,等后面分析。
当一个OkHttpClient构造好之后,调用newCall(Request request)方法产生一个Call对象,下面看一个实现了Call接口的类RealCall。
@Override
public Response execute() throws IOException {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
try {
client.dispatcher().executed(this);
Response result = getResponseWithInterceptorChain(false);
if (result == null) throw new IOException("Canceled");
return result;
} finally {
client.dispatcher().finished(this);
}
}
重点看Response是怎么得到的。
private Response getResponseWithInterceptorChain(boolean forWebSocket) throws IOException {
Interceptor.Chain chain = new ApplicationInterceptorChain(0, originalRequest, forWebSocket);
return chain.proceed(originalRequest);
}
Response是由ApplicationInterceptorChain来得到的。
@Override public Response proceed(Request request) throws IOException {
// If there's another interceptor in the chain, call that.
if (index < client.interceptors().size()) {
Interceptor.Chain chain = new ApplicationInterceptorChain(index + 1, request, forWebSocket);
Interceptor interceptor = client.interceptors().get(index);
Response interceptedResponse = interceptor.intercept(chain);
if (interceptedResponse == null) {
throw new NullPointerException("application interceptor " + interceptor + " returned null");
}
return interceptedResponse;
}
// No more interceptors. Do HTTP. return getResponse(request, forWebSocket);
}
到底所谓拦截器Interceptor和链Chain是干嘛的呢?注释说了:
Observes, modifies, and potentially short-circuits requests going out and the corresponding* responses coming back in. Typically interceptors add, remove, or transform headers on the request* or response.
大概意思就是观察/修改/短路请求发出和短路回来的响应。通常拦截器增加/移除或转化request/response的头部。
public interface Interceptor {
Response intercept(Chain chain) throws IOException;
interface Chain {
Request request();
Response proceed(Request request) throws IOException;
Connection connection();
}
}
下面是ApplicationInterceptorChain对Interceptor.Chain的proceed(Request r)方法的具体实现:
@Override public Response proceed(Request request) throws IOException {
// If there's another interceptor in the chain, call that.
if (index < client.interceptors().size()) {
Interceptor.Chain chain = new ApplicationInterceptorChain(index + 1, request, forWebSocket);
Interceptor interceptor = client.interceptors().get(index);
Response interceptedResponse = interceptor.intercept(chain);
if (interceptedResponse == null) {
throw new NullPointerException("application interceptor " + interceptor + " returned null");
} return interceptedResponse;
}
// No more interceptors. Do HTTP.
return getResponse(request, forWebSocket);
}
拦截器起什么作用,这里要搞清楚,似乎很重要。
关键点在最后一句,这里返回了Response。
Response getResponse(Request request, boolean forWebSocket) throws IOException {
// Copy body metadata to the appropriate request headers.
RequestBody body = request.body();
if (body != null) {
Request.Builder requestBuilder = request.newBuilder();
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");
}
request = requestBuilder.build();
}
// Create the initial HTTP engine. Retries and redirects need new engine for each attempt.
engine = new HttpEngine(client, request, false, false, forWebSocket, null, null, null);
int followUpCount = 0; while (true) {
if (canceled) {
engine.releaseStreamAllocation();
throw new IOException("Canceled");
}
boolean releaseConnection = true;
try {
engine.sendRequest();
engine.readResponse();
releaseConnection = false;
} catch (RequestException e) {
// The attempt to interpret the request failed. Give up.
throw e.getCause();
} catch (RouteException e) {
// The attempt to connect via a route failed. The request will not have been sent.
HttpEngine retryEngine = engine.recover(e.getLastConnectException(), true, null);
if (retryEngine != null) {
releaseConnection = false;
engine = retryEngine;
continue;
}
// Give up; recovery is not possible.
throw e.getLastConnectException();
} catch (IOException e) {
// An attempt to communicate with a server failed. The request may have been sent.
HttpEngine retryEngine = engine.recover(e, false, null);
if (retryEngine != null) {
releaseConnection = false;
engine = retryEngine;
continue;
}
// Give up; recovery is not possible.
throw e;
} finally {
// We're throwing an unchecked exception. Release any resources.
if (releaseConnection) {
StreamAllocation streamAllocation = engine.close();
streamAllocation.release();
}
}
Response response = engine.getResponse();
Request followUp = engine.followUpRequest();
if (followUp == null) {
if (!forWebSocket) {
engine.releaseStreamAllocation();
}
return response;
}
StreamAllocation streamAllocation = engine.close();
if (++followUpCount > MAX_FOLLOW_UPS) {
streamAllocation.release();
throw new ProtocolException("Too many follow-up requests: " + followUpCount);
}
if (!engine.sameConnection(followUp.url())) {
streamAllocation.release();
streamAllocation = null;
}
else if (streamAllocation.stream() != null) {
throw new IllegalStateException("Closing the body of " + response + " didn't close its backing stream. Bad interceptor?");
}
request = followUp;
engine = new HttpEngine(client, request, false, false, forWebSocket, streamAllocation, null, response);
}
}
发现HTTP请求/响应发生的核心,是HttpEngine这个类。
engine.sendRequest();
engine.readResponse();
大概是这两个方法调用之后,就可以从engine中取出Response了。
Response response = engine.getResponse();
那么在HttpEngine调sendRequest()方法时,发生了什么事呢?
我把这个方法的注释摘抄一下:
Figures out what the response source will be, and opens a socket to that source if necessary. Prepares the request headers and gets ready to start writing the request body if it exists.
大意:指明response源是什么样子,打开一个socket连接到那个response源上,准备请求头并做好开始写请求体的准备。
然后看一下readResponse()这个方法做了什么事情。
Flushes the remaining request header and body, parses the HTTP response headers and starts reading the HTTP response body if it exists.
大意是将剩余的请求头和请求头清除出来,然后解析HTTP响应头,开始读取HTTP响应体。
未完,待续。
下午要出去面试了。不知道又会是个什么鬼样。