接着上一篇解析,主要是HttpEngine,这个类中有三个重要方法,也是OkHttp的主要方法:发送请求—-sendRequest(),读取响应—–readResponse(),处理重定向——-followUpRequest()。
一、发送请求—-sendRequest()
/**
* 找出响应源是什么,同时,如果有需要,会打开一个套接字到该响应源。准备请求头部,并准备开始写入请求正文,如果响应源存在。
*/
public void sendRequest() throws RequestException, RouteException, IOException {
if (cacheStrategy != null) return; // Already sent.
if (transport != null) throw new IllegalStateException();
//根据userRequest初始化一个新的Request
Request request = networkRequest(userRequest);
//根据OkHttpClient得到缓存
InternalCache responseCache = Internal.instance.internalCache(client);
//如果缓存响应可用,即responseCache不为null,则根据键"request"从Cache中取出response
Response cacheCandidate = responseCache != null
? responseCache.get(request)
: null;
long now = System.currentTimeMillis();
cacheStrategy = new CacheStrategy.Factory(now, request, cacheCandidate).get();
networkRequest = cacheStrategy.networkRequest;
cacheResponse = cacheStrategy.cacheResponse;
//缓存可用
if (responseCache != null) {
responseCache.trackResponse(cacheStrategy);
}
//缓存不可用,就关闭。
if (cacheCandidate != null && cacheResponse == null) {
closeQuietly(cacheCandidate.body());
}
//networkRequest != null,说明网络可用,且cache不可用
if (networkRequest != null) {
//建立一个新连接,除非从重定向中继承一个connection
if (connection == null) {
connect();
}
transport = Internal.instance.newTransport(connection, this);
if (callerWritesRequestBody && permitsRequestBody() && requestBodyOut == null) {
long contentLength = OkHeaders.contentLength(request);
if (bufferRequestBody) {
if (contentLength > Integer.MAX_VALUE) {
throw new IllegalStateException("Use setFixedLengthStreamingMode() or "
+ "setChunkedStreamingMode() for requests larger than 2 GiB.");
}
if (contentLength != -1) { transport.writeRequestHeaders(networkRequest);
requestBodyOut = new RetryableSink((int) contentLength);
} else {
requestBodyOut = new RetryableSink();
}
} else {
transport.writeRequestHeaders(networkRequest);
requestBodyOut = transport.createRequestBody(networkRequest, contentLength);
}
}
} else {//networkRequest为null, 要么cache可用,要么网络被禁止使用
// We aren't using the network. Recycle a connection we may have inherited from a redirect.
if (connection != null) {
Internal.instance.recycle(client.getConnectionPool(), connection);
connection = null;
}
if (cacheResponse != null) {
//缓存响应可用,就通过cacheResponse给userResponse赋值
// We have a valid cached response. Promote it to the user response immediately.
this.userResponse = cacheResponse.newBuilder()
.request(userRequest)
.priorResponse(stripBody(priorResponse))
.cacheResponse(stripBody(cacheResponse))
.build();
} else {
//如果网络被禁止使用,且缓存不可用,就构造一个504的Response,并赋值给userResponse
this.userResponse = new Response.Builder()
.request(userRequest)
.priorResponse(stripBody(priorResponse))
.protocol(Protocol.HTTP_1_1)
.code(504)
.message("Unsatisfiable Request (only-if-cached)")
.body(EMPTY_BODY)
.build();
}
//根据缓存response 或者 自己构造的504 Response进行gzip压缩
userResponse = unzip(userResponse);
}
}
中间有用到缓存处理策略
public final class CacheStrategy {
//返回一个策略以满足使用缓存响应的request
public CacheStrategy get() {
CacheStrategy candidate = getCandidate();
if (candidate.networkRequest != null && request.cacheControl().onlyIfCached()) {
//网络被禁止使用,且cache不可用,就创建新的CacheStrategy
// We're forbidden from using the network and the cache is insufficient.
return new CacheStrategy(null, null);
}
return candidate;
}
/** 返回一个策略以取得可以使用网络的request */
private CacheStrategy getCandidate() {
// 没有cacheResponse,也就是cache不可用
if (cacheResponse == null) {
//最终就是走网络,所以把第二个参数置为null
return new CacheStrategy(request, null);
}
//对于https,如果缺少必要的握手,则删除该缓存响应,认为cache不可用。
if (request.isHttps() && cacheResponse.handshake() == null) {
//最终就是走网络,所以把第二个参数置为null
return new CacheStrategy(request, null);
}
if (!isCacheable(cacheResponse, request)) {
//最终就是走网络,所以把第二个参数置为null
return new CacheStrategy(request, null);
}
CacheControl requestCaching = request.cacheControl();
if (requestCaching.noCache() || hasConditions(request)) {
//最终就是走网络,所以把第二个参数置为null
return new CacheStrategy(request, null);
}
//判断cache是否过期:通过是否过期,最后修改时间等
long ageMillis = cacheResponseAge();
long freshMillis = computeFreshnessLifetime();
if (requestCaching.maxAgeSeconds() != -1) {
freshMillis = Math.min(freshMillis, SECONDS.toMillis(requestCaching.maxAgeSeconds()));
}
省略........
//如果cacheResponse可用,且不过期,就使用缓存,不走网络
return new CacheStrategy(null, builder.build());
}
Request.Builder conditionalRequestBuilder = request.newBuilder();
省略........
}
}
二、读取响应—–readResponse()
/*** 刷新剩余的请求头和正文,解析http响应头,并且开始读取http响应正文,前提是正文存在。*/
public void readResponse() throws IOException {
if (userResponse != null) {
return; // Already ready.
}
//网络不可用,且缓存不可用
if (networkRequest == null && cacheResponse == null) {
throw new IllegalStateException("call sendRequest() first!");
}
//如果网络不可用,则说明没有可读取的响应体,就不再往下执行
if (networkRequest == null) {
return; // No network response to read.
}
Response networkResponse;
if (forWebSocket) {
//将header写入socket
transport.writeRequestHeaders(networkRequest);
//发送request,并读取response
networkResponse = readNetworkResponse();
} else if (!callerWritesRequestBody) {
//先执行拦截器,再发送request,并读取response
networkResponse = new com.squareup.okhttp.internal.http.HttpEngine.NetworkInterceptorChain(0, networkRequest).proceed(networkRequest);
} else {
//发送请求体buffer
// Emit the request body's buffer so that everything is in requestBodyOut.
if (bufferedRequestBody != null && bufferedRequestBody.buffer().size() > 0) {
bufferedRequestBody.emit();
}
// Emit the request headers if we haven't yet. We might have just learned the Content-Length.
if (sentRequestMillis == -1) {
if (OkHeaders.contentLength(networkRequest) == -1
&& requestBodyOut instanceof RetryableSink) {
long contentLength = ((RetryableSink) requestBodyOut).contentLength();
networkRequest = networkRequest.newBuilder()
.header("Content-Length", Long.toString(contentLength))
.build();
}
//写入到socket
transport.writeRequestHeaders(networkRequest);
}
// 将请求体写入到socket
if (requestBodyOut != null) {
if (bufferedRequestBody != null) {
// This also closes the wrapped requestBodyOut.
bufferedRequestBody.close();
} else {
requestBodyOut.close();
}
if (requestBodyOut instanceof RetryableSink) {
transport.writeRequestBody((RetryableSink) requestBodyOut);
}
}
networkResponse = readNetworkResponse();
}
receiveHeaders(networkResponse.headers());
// 如果缓存可用,且不过期,就使用缓存response
if (cacheResponse != null) {
if (validate(cacheResponse, networkResponse)) {
userResponse = cacheResponse.newBuilder()
.request(userRequest)
.priorResponse(stripBody(priorResponse))
.headers(combine(cacheResponse.headers(), networkResponse.headers()))
.cacheResponse(stripBody(cacheResponse))
.networkResponse(stripBody(networkResponse))
.build();
networkResponse.body().close();
releaseConnection();
// Update the cache after combining headers but before stripping the
// Content-Encoding header (as performed by initContentStream()).
InternalCache responseCache = Internal.instance.internalCache(client);
responseCache.trackConditionalCacheHit();
responseCache.update(cacheResponse, stripBody(userResponse));
userResponse = unzip(userResponse);
return;
} else {
closeQuietly(cacheResponse.body());
}
}
//根据networkResponse构造response,并将其缓存
userResponse = networkResponse.newBuilder()
.request(userRequest)
.priorResponse(stripBody(priorResponse))
.cacheResponse(stripBody(cacheResponse))
.networkResponse(stripBody(networkResponse))
.build();
if (hasBody(userResponse)) {
maybeCache();
userResponse = unzip(cacheWritingResponse(storeRequest, userResponse));
}
}
还有中间方法
private Response readNetworkResponse() throws IOException {
//将请求刷新出去
transport.finishRequest();
//读取response headers并构造networkResponse
Response networkResponse = transport.readResponseHeaders()
.request(networkRequest)
.handshake(connection.getHandshake())
.header(OkHeaders.SENT_MILLIS, Long.toString(sentRequestMillis))
.header(OkHeaders.RECEIVED_MILLIS, Long.toString(System.currentTimeMillis()))
.build();
if (!forWebSocket) {
networkResponse = networkResponse.newBuilder()
.body(transport.openResponseBody(networkResponse))
.build();
}
Internal.instance.setProtocol(connection, networkResponse.protocol());
return networkResponse;
}
三、followUpRequest()
这个就是用来处理重定向的