上一篇Okhttp3源码分析(二)讲了核心类Dispatcher,下面继续往深层次讲述Okhttp3的奥秘
一、HttpEngine(Http引擎类)
首先看一下构造函数
public HttpEngine(OkHttpClient client, Request request, boolean bufferRequestBody,
boolean callerWritesRequestBody, boolean forWebSocket, StreamAllocation streamAllocation,
RetryableSink requestBodyOut, Response priorResponse) {
this.client = client;
this.userRequest = request;
this.bufferRequestBody = bufferRequestBody;
this.callerWritesRequestBody = callerWritesRequestBody;
this.forWebSocket = forWebSocket;
this.streamAllocation = streamAllocation != null
? streamAllocation
: new StreamAllocation(client.connectionPool(), createAddress(client, request));
this.requestBodyOut = requestBodyOut;
this.priorResponse = priorResponse;
}
- client 声明的OkHttpClient
- request 声明的Request
- streamAllocation 管理connect的类
- requestBodyOut 用于重试时候
- priorResponse 用于重定向时候返回的response
看一下sendRequest()
public void sendRequest() throws RequestException, RouteException, IOException {
if (cacheStrategy != null) return; // Already sent.
if (httpStream != null) throw new IllegalStateException();
//组装header
Request request = networkRequest(userRequest);
//这个其实就是Cache里的final InternalCache internalCache = new InternalCache()
InternalCache responseCache = Internal.instance.internalCache(client);
//获取缓存的response
Response cacheCandidate = responseCache != null
? responseCache.get(request)
: null;
long now = System.currentTimeMillis();
cacheStrategy = new CacheStrategy.Factory(now, request, cacheCandidate).get();
//就是传入的request
networkRequest = cacheStrategy.networkRequest;
//传入的cacheCandidate转化的cacheResponse
cacheResponse = cacheStrategy.cacheResponse;
//不会null代表OkHttpClient设置了cache
if (responseCache != null) {
//Cache.trackResponse(cacheStrategy) 对networkRequest和cacheResponse进行判断
responseCache.trackResponse(cacheStrategy);
}
//缓存的response!=null,但是cacheResponse==null,可判断该缓存已经失效
if (cacheCandidate != null && cacheResponse == null) {
closeQuietly(cacheCandidate.body()); // The cache candidate wasn't applicable. Close it.
}
// If we're forbidden from using the network and the cache is insufficient, fail.
//都为null 组装userResponse
if (networkRequest == null && cacheResponse == null) {
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();
return;
}
// If we don't need the network, we're done.
if (networkRequest == null) {
//设置userResponse为缓存的response
userResponse = cacheResponse.newBuilder()
.request(userRequest)
.priorResponse(stripBody(priorResponse))
.cacheResponse(stripBody(cacheResponse))
.build();
userResponse = unzip(userResponse);
return;
}
// We need the network to satisfy this request. Possibly for validating a conditional GET.
boolean success = false;
try {
//Http1xStream对象 真正socket连接 tcp连接的地方
httpStream = connect();
httpStream.setHttpEngine(this);
//不重定向的时候为false,反之为true
if (writeRequestHeadersEagerly()) {
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) {
// Buffer a request body of a known length.
httpStream.writeRequestHeaders(networkRequest);
requestBodyOut = new RetryableSink((int) contentLength);
} else {
// Buffer a request body of an unknown length. Don't write request headers until the
// entire body is ready; otherwise we can't set the Content-Length header correctly.
requestBodyOut = new RetryableSink();
}
} else {
httpStream.writeRequestHeaders(networkRequest);
requestBodyOut = httpStream.createRequestBody(networkRequest, contentLength);
}
}
success = true;
} finally {
// If we're crashing on I/O or otherwise, don't leak the cache body.
if (!success && cacheCandidate != null) {
//没有成功,但是有缓存,清除缓存
closeQuietly(cacheCandidate.body());
}
}
}
private Request networkRequest(Request request) throws IOException {
Request.Builder result = request.newBuilder();
if (request.header("Host") == null) {
result.header("Host", hostHeader(request.url(), false));
}
if (request.header("Connection") == null) {
result.header("Connection", "Keep-Alive");
}
if (request.header("Accept-Encoding") == null) {
transparentGzip = true;
result.header("Accept-Encoding", "gzip");
}
List<Cookie> cookies = client.cookieJar().loadForRequest(request.url());
if (!cookies.isEmpty()) {
result.header("Cookie", cookieHeader(cookies));
}
if (request.header("User-Agent") == null) {
result.header("User-Agent", Version.userAgent());
}
return result.build();
}
主要做了
- 组装request的header
- 判断是否有可用的缓存,有的话就赋值给userResponse
- 没有可用缓存发起socket连接
- 有重定向的时候组装一些参数
- 如果连接失败并且有缓存,就清除缓存
然后再看一下readResponse
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) {
httpStream.writeRequestHeaders(networkRequest);
networkResponse = readNetworkResponse();
} else if (!callerWritesRequestBody) {
//网络拦截器 对response进行封装
networkResponse = new NetworkInterceptorChain(0, networkRequest).proceed(networkRequest);
} else {
// 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();
}
httpStream.writeRequestHeaders(networkRequest);
}
// Write the request body to the socket.
if (requestBodyOut != null) {
if (bufferedRequestBody != null) {
// This also closes the wrapped requestBodyOut.
bufferedRequestBody.close();
} else {
requestBodyOut.close();
}
if (requestBodyOut instanceof RetryableSink) {
httpStream.writeRequestBody((RetryableSink) requestBodyOut);
}
}
//读取网络请求回来的response
networkResponse = readNetworkResponse();
}
receiveHeaders(networkResponse.headers());
// If we have a cache response too, then we're doing a conditional get.
//不为null,缓存更新为最新的networkResponse
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();
releaseStreamAllocation();
// 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组装userResponse
userResponse = networkResponse.newBuilder()
.request(userRequest)
.priorResponse(stripBody(priorResponse))
.cacheResponse(stripBody(cacheResponse))
.networkResponse(stripBody(networkResponse))
.build();
//如果有body
if (hasBody(userResponse)) {
maybeCache();
//看后端是否支持Gzip,根据Gzip压缩
userResponse = unzip(cacheWritingResponse(storeRequest, userResponse));
}
}
主要做了
- 网络拦截器 进行相应处理
- networkResponse中的cookies存入OkHttpClient中的cookieJar中,该对象默认是空的,如果我们在构造OkHttpClient的时候给予它一个CookieJar那么OkHttpClient就会将每次获得的cookie都存入我们定义的CookieJar中。一般是把url作为key,cookies作为value
- 如果该请求有缓存就更新缓存
- 根据networkResponse组装userResponse
- 看是否需要缓存 只缓存GET方法
看一下readResponse()里的readNetworkResponse()
private Response readNetworkResponse() throws IOException {
httpStream.finishRequest();
Response networkResponse = httpStream.readResponseHeaders()
.request(networkRequest)
.handshake(streamAllocation.connection().handshake())
.header(OkHeaders.SENT_MILLIS, Long.toString(sentRequestMillis))
.header(OkHeaders.RECEIVED_MILLIS, Long.toString(System.currentTimeMillis()))
.build();
if (!forWebSocket) {
networkResponse = networkResponse.newBuilder()
.body(httpStream.openResponseBody(networkResponse))
.build();
}
if ("close".equalsIgnoreCase(networkResponse.request().header("Connection"))
|| "close".equalsIgnoreCase(networkResponse.header("Connection"))) {
streamAllocation.noNewStreams();
}
return networkResponse;
}
上面就是组装networkResponse