一,源码精髓责任链模式分析
1. 最终执行到AsyncCall这个类的eecute这个方法,在这个方法中真正的开始网络操作,并将它们通过回调返回给网络请求者
@Override protected void execute() {
boolean signalledCallback = false;
try {
Response response = getResponseWithInterceptorChain();
if (retryAndFollowUpInterceptor.isCanceled()) {
signalledCallback = true;
responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
} else {
signalledCallback = true;
responseCallback.onResponse(RealCall.this, response);
}
} catch (IOException e) {
if (signalledCallback) {
// Do not signal the callback twice!
Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e);
} else {
eventListener.callFailed(RealCall.this, e);
responseCallback.onFailure(RealCall.this, e);
}
} finally {
client.dispatcher().finished(this);
}
}
1.1 先来看着一行代码 Response response = getResponseWithInterceptorChain(); 我们通过getResponseWithInterceptorChain方法去得到一个响应,这个方法内部置有很多拦截器,这些拦截器内部各自对请求做了一些操作,然后包装成响应返回。
Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
// 拦截器的一个集合
List<Interceptor> interceptors = new ArrayList<>();
// 客户端的所有自定义拦截器(我们在Request中自定义的)
interceptors.addAll(client.interceptors());// 自己的
// OKhttp 5 个拦截器 ,责任链设计模式,每一个拦截器只处理与他相关的部分 volley
interceptors.add(retryAndFollowUpInterceptor);// 重试
interceptors.add(new BridgeInterceptor(client.cookieJar()));// 基础
interceptors.add(new CacheInterceptor(client.internalCache()));// 缓存
interceptors.add(new ConnectInterceptor(client));// 建立连接
interceptors.add(new CallServerInterceptor(forWebSocket));// 写数据
Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
originalRequest, this, eventListener, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis());
return chain.proceed(originalRequest);
}
1.2 Intercepter 是一个接口,内部还又一个子接口 chain
public interface Interceptor {
Response intercept(Chain chain) throws IOException;
interface Chain {
Request request();
Response proceed(Request request) throws IOException;
/**
* Returns the connection the request will be executed on. This is only available in the chains
* of network interceptors; for application interceptors this is always null.
*/
@Nullable Connection connection();
Call call();
int connectTimeoutMillis();
Chain withConnectTimeout(int timeout, TimeUnit unit);
int readTimeoutMillis();
Chain withReadTimeout(int timeout, TimeUnit unit);
int writeTimeoutMillis();
Chain withWriteTimeout(int timeout, TimeUnit unit);
}
}
1.3 RealInterceptorChain这个类是Chain接口的实现类将客户端和OkhttpCliet定义的拦截器添加到一个集合中List<Interceptor> interceptors,再将这个集合添加到RealInterceptorChain里面,然后通过process这个方法 ,依照集合的顺序执行这些插值器,并最终封装成一个response返回给RealCall,RealCall再通过回调将response返回给网络请求者。
public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
RealConnection connection) throws IOException {
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");
}
// Call the next interceptor in the chain.
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;
}
二我们来看一下Okhttp的五种拦截器
1.RetryAndFollowUpIntercepter (重试)
@Override public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
RealInterceptorChain realChain = (RealInterceptorChain) chain;
Call call = realChain.call();
EventListener eventListener = realChain.eventListener();
streamAllocation = new StreamAllocation(client.connectionPool(), createAddress(request.url()),
call, eventListener, callStackTrace);
int followUpCount = 0;
Response priorResponse = null;
while (true) {
// 一个死循环 ,重试, 两种情况可以终止 return Response, throws IOException
if (canceled) {
streamAllocation.release();
throw new IOException("Canceled");
}
Response response;
boolean releaseConnection = true;
try {
// 丢给下一个拦截器去处理,会有异常的情况
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.
// 先处理 RouteException
if (!recover(e.getLastConnectException(), false, request)) {
throw e.getLastConnectException();
}
releaseConnection = false;
continue;
} catch (IOException e) {
// 处理 IOException
// An attempt to communicate with a server failed. The request may have been sent.
boolean requestSendStarted = !(e instanceof ConnectionShutdownException);
if (!recover(e, 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();
}
// 从下面过了一个 Response ,但是这个 Response 不能够直接返回给上一级,会有重定向
// 重定向 返回码是 307 ,从头部的 Location 里面获取新的链接 重新请求一次
Request followUp = followUpRequest(response);
if (followUp == null) {
if (!forWebSocket) {
streamAllocation.release();
}
// 直接返回给上一级
return response;
}
closeQuietly(response.body());
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);
} else if (streamAllocation.codec() != null) {
throw new IllegalStateException("Closing the body of " + response
+ " didn't close its backing stream. Bad interceptor?");
}
// 请求就变为了重试的请求 Request
request = followUp;
priorResponse = response;
}
}
1.1处理重试的一个拦截器,会处理一些异常,只要不是致命的异常就会重新发一次请求(把request发给下级),如果是致命的异常就会抛给上一级(即调用者)
1.1.1 再RealCall的getResponseWithInterceptorChain这个方法中,调用chain.proceed(originalRequest)这个方法就可以从第一个开始只能怪Interceptor了,轮回执行拦截器的代码再RealInterceptor 中的process方法中 如下:
RealConnection connection) throws IOException {
if (index >= interceptors.size()) throw new AssertionError();
RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
writeTimeout);
//这里 index + 1 是说的是此时传入的索引为1 但是当前的index = 0
//2 1
//3 2
//4 3
//5 4 执行完这一次 应为5>=5 所以爆出异常,不能再执行下去了
Interceptor interceptor = interceptors.get(index);
Response response = interceptor.intercept(next);
return response;
1.1.2 第一个执行的拦截器就是RetryAndFollowUpIntercepter
1.1.2.1 第一步会先从上一级获得request
//从上一级获取Request(因为是同一块内存,所以收到的request经过拦截器处理处理之后的Request)
Request request = chain.request();
1.1.2.2 注意这俩个参数 ,后面还会用到
int followUpCount = 0; //记录重定向的次数
//这个是重试拦截器最终的响应,并且且这个响应会回调给调用者
Response priorResponse = null;
1.1.2.3 再之后是一个while的死循环, 这个死循环只有再这两种情况下才可以终止 一是 :return Response, 二是 :throws IOException
然后执行
// 这是执行的第一个拦截器,丢给下一个拦截器去处理,会有异常的情况
response = realChain.proceed(request, streamAllocation, null, null);
releaseConnection = false;
如果发生异常,就执行: 分致命异常和非致命异常俩种情况。
// 先处理 RouteException
if (!recover(e.getLastConnectException(), false, request)) {
//如过拿到的是一个致命的异常,就返回上一级
throw e.getLastConnectException();
}
releaseConnection = false;
//如果不是致命的异常,就再执行一遍上述代码
continue;
} catch (IOException e) {
// 处理 IOException
// An attempt to communicate with a server failed. The request may have been sent.
boolean requestSendStarted = !(e instanceof ConnectionShutdownException);
if (!recover(e, requestSendStarted, request)) throw e;
releaseConnection = false;
continue;
不论请求是否发生异常,最后都会执行finnaly中的语句
finally {
if (priorResponse != null) {
response = response.newBuilder()
.priorResponse(priorResponse.newBuilder()
.body(null)
.build())
.build();
}
// 从下面过了一个 Response ,但是这个 Response 不能够直接返回给上一级,会有重定向
// 重定向 返回码是 307 ,从头部的 Location 里面获取新的链接 重新请求一次
Request followUp = followUpRequest(response);
if (followUp == null) {
//等于空,说明不需要处理状态码,直接返回就可以了
if (!forWebSocket) {
streamAllocation.release();
}
// 直接返回给上一级
return response;
}
// 如果followUp不等于空,请求就变为了重试的请求 Request
//因为这一段代码处于死循环,所以有一次开始执行这一段代码
request = followUp;
priorResponse = response;
}
1.1.2.4 其中方法 Request followUp = followUpRequest(response); 是对状态码的一些处理
private Request followUpRequest(Response userResponse) throws IOException {
if (userResponse == null) throw new IllegalStateException();
Connection connection = streamAllocation.connection();
Route route = connection != null
? connection.route()
: null;
int responseCode = userResponse.code();
final String method = userResponse.request().method();
// 对状态码进行判断
switch (responseCode) {
case HTTP_PROXY_AUTH:
Proxy selectedProxy = route != null
? route.proxy()
: client.proxy();
if (selectedProxy.type() != Proxy.Type.HTTP) {
throw new ProtocolException("Received HTTP_PROXY_AUTH (407) code while not using proxy");
}
return client.proxyAuthenticator().authenticate(route, userResponse);
case HTTP_UNAUTHORIZED:
return client.authenticator().authenticate(route, userResponse);
case HTTP_PERM_REDIRECT:
case HTTP_TEMP_REDIRECT:
// "If the 307 or 308 status code is received in response to a request other than GET
// or HEAD, the user agent MUST NOT automatically redirect the request"
if (!method.equals("GET") && !method.equals("HEAD")) {
return null;
}
// fall-through
case HTTP_MULT_CHOICE:
case HTTP_MOVED_PERM:
case HTTP_MOVED_TEMP:
case HTTP_SEE_OTHER:
// Does the client allow redirects?
if (!client.followRedirects()) return null;
// 从头部信息里面 获取 Location 新的链接
String location = userResponse.header("Location");
if (location == null) return null;
// 生成一个新的 HttpUrl
HttpUrl url = userResponse.request().url().resolve(location);
// Don't follow redirects to unsupported protocols.
if (url == null) return null;
// If configured, don't follow redirects between SSL and non-SSL.
boolean sameScheme = url.scheme().equals(userResponse.request().url().scheme());
if (!sameScheme && !client.followSslRedirects()) return null;
// Most redirects don't include a request body.
Request.Builder requestBuilder = userResponse.request().newBuilder();
if (HttpMethod.permitsRequestBody(method)) {
final boolean maintainBody = HttpMethod.redirectsWithBody(method);
if (HttpMethod.redirectsToGet(method)) {
requestBuilder.method("GET", null);
} else {
RequestBody requestBody = maintainBody ? userResponse.request().body() : null;
requestBuilder.method(method, requestBody);
}
if (!maintainBody) {
requestBuilder.removeHeader("Transfer-Encoding");
requestBuilder.removeHeader("Content-Length");
requestBuilder.removeHeader("Content-Type");
}
}
// When redirecting across hosts, drop all authentication headers. This
// is potentially annoying to the application layer since they have no
// way to retain them.
if (!sameConnection(userResponse, url)) {
requestBuilder.removeHeader("Authorization");
}
// 返回一个新链接的 Request
return requestBuilder.url(url).build();
case HTTP_CLIENT_TIMEOUT:
// 408's are rare in practice, but some servers like HAProxy use this response code. The
// spec says that we may repeat the request without modifications. Modern browsers also
// repeat the request (even non-idempotent ones.)
if (!client.retryOnConnectionFailure()) {
// The application layer has directed us not to retry the request.
return null;
}
if (userResponse.request().body() instanceof UnrepeatableRequestBody) {
return null;
}
if (userResponse.priorResponse() != null
&& userResponse.priorResponse().code() == HTTP_CLIENT_TIMEOUT) {
// We attempted to retry and got another timeout. Give up.
return null;
}
return userResponse.request();
default:
return null;
}
}
2.BridgeInterceptor
做一个简单的处理,设置一些通用的请求头,Content-Type, Connection,Content-Length ,Cookie 做一些返回处理,如果返回的数据被压缩了,采用ZIPSource, 保存Cookie。
3 . CacheIntercepter
3.1 再缓存可用的情况下,会取读取本地的缓存数据,如果没有直接去服务器,如果有,首先判断有没有缓存策略,然后判断有没有过期,如果没有过期直接那缓存,如果过期需要添加一些之前的头部信息如If-Modified-since,这个时候后台服务器有可能会返回304,代表你还是可以拿本地缓存,每次读取到新的响应后做一次缓存。
@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();
// networkRequest 还不知道是啥 networkRequest 做了处理
Request networkRequest = strategy.networkRequest;
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.
}
// If we're forbidden from using the network and the cache is insufficient, fail.
// 如果请求的 networkRequest 是空,缓存的 cacheResponse 是空我就返回 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 we don't need the network, we're done.
if (networkRequest == null) {
// 如果缓存策略里面的 networkRequest 是空,那么就 返回 缓存好的 Response
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());
}
}
// If we have a cache response too, then we're doing a conditional get.
// 处理返回,处理 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 response = networkResponse.newBuilder()
.cacheResponse(stripBody(cacheResponse))
.networkResponse(stripBody(networkResponse))
.build();
if (cache != null) {
// 然后缓存获取的 Response
if (HttpHeaders.hasBody(response) && CacheStrategy.isCacheable(response, networkRequest)) {
// Offer this request to the cache.
CacheRequest cacheRequest = cache.put(response);
return cacheWritingResponse(cacheRequest, response);
}
if (HttpMethod.invalidatesCache(networkRequest.method())) {
try {
cache.remove(networkRequest);
} catch (IOException ignored) {
// The cache cannot be written.
}
}
}
return response;
}
3.2 这个方法的第一步 是从缓存中获取响应
// 从缓存里面拿,到底怎么拿?放一边
Response cacheCandidate = cache != null
? cache.get(chain.request())
: null;
3.3第二步是构建一个缓存策略
long now = System.currentTimeMillis();
// 构建了一个缓存策略
CacheStrategy strategy = new CacheStrategy.Factory(now, chain.request(), cacheCandidate).get();
// networkRequest 还不知道是啥 networkRequest 做了处理
Request networkRequest = strategy.networkRequest;
Response cacheResponse = strategy.cacheResponse;
3.3.1解析这一句 CacheStrategy strategy = new CacheStrategy.Factory(now, chain.request(), cacheCandidate).get();
3.3.1.1 看CacheStrategy的Factory(工厂模式)这个方法
//nowMillis 开始请求缓存的时间
//最原始的请求
//从缓存当中获取的缓存响应
public Factory(long nowMillis, Request request, Response cacheResponse) {
this.nowMillis = nowMillis; //这个当前的事件
this.request = request; //这个是原始的request
this.cacheResponse = cacheResponse;
if (cacheResponse != null) {
this.sentRequestMillis = cacheResponse.sentRequestAtMillis();
this.receivedResponseMillis = cacheResponse.receivedResponseAtMillis();
Headers headers = cacheResponse.headers();
for (int i = 0, size = headers.size(); i < size; i++) {
String fieldName = headers.name(i);
String value = headers.value(i);
// 解析之前缓存好的一些头部信息,服务器给的 Expires 缓存的过去时间,Last-Modified 服务器上次数据的更新时间
if ("Date".equalsIgnoreCase(fieldName)) {
servedDate = HttpDate.parse(value);
servedDateString = value;
} else if ("Expires".equalsIgnoreCase(fieldName)) {
expires = HttpDate.parse(value);
} else if ("Last-Modified".equalsIgnoreCase(fieldName)) {
lastModified = HttpDate.parse(value);
lastModifiedString = value;
} else if ("ETag".equalsIgnoreCase(fieldName)) {
etag = value;
} else if ("Age".equalsIgnoreCase(fieldName)) {
ageSeconds = HttpHeaders.parseSeconds(value, -1);
}
}
}
}
3.3.1.2 再来看 get();方法
public CacheStrategy get() {
//通过getCandidate()这个方法去 调整和选择缓存的策略
CacheStrategy candidate = getCandidate();
// 除了 这种 onlyIfCached 只能从缓存里面获取响应的策略
// networkRequest = null cacheResponse = null
if (candidate.networkRequest != null && request.cacheControl().onlyIfCached()) {
// We're forbidden from using the network and the cache is insufficient.
return new CacheStrategy(null, null);
}
//其他的直接将这种策略返回就可以了
return candidate;
}
3.3.1.3 再来看看 getCandidate() 方法
private CacheStrategy getCandidate() {
//第一种策略
// 如果没有缓存的话
if (cacheResponse == null) {
//直接返回 让响应 这样在全局中 networkRequest=request cacheResponse=null
return new CacheStrategy(request, null);
}
//第二种策略
// 要不要缓存,缓存策略,Public、private、no-cache、max-age
if (!isCacheable(cacheResponse, request)) { //不需要缓存
return new CacheStrategy(request, null);
}
//第三种策略 noCache
CacheControl requestCaching = request.cacheControl();
if (requestCaching.noCache() || hasConditions(request)) {
return new CacheStrategy(request, null);
}
//第四种策略 onlyIfCached
CacheControl responseCaching = cacheResponse.cacheControl();
if (responseCaching.immutable()) {
return new CacheStrategy(null, cacheResponse);
}
// 缓存策略 + 过期时间 public private max-Age
long ageMillis = cacheResponseAge();
long freshMillis = computeFreshnessLifetime();
if (requestCaching.maxAgeSeconds() != -1) {
freshMillis = Math.min(freshMillis, SECONDS.toMillis(requestCaching.maxAgeSeconds()));
}
long minFreshMillis = 0;
if (requestCaching.minFreshSeconds() != -1) {
minFreshMillis = SECONDS.toMillis(requestCaching.minFreshSeconds());
}
long maxStaleMillis = 0;
if (!responseCaching.mustRevalidate() && requestCaching.maxStaleSeconds() != -1) {
maxStaleMillis = SECONDS.toMillis(requestCaching.maxStaleSeconds());
}
if (!responseCaching.noCache() && ageMillis + minFreshMillis < freshMillis + maxStaleMillis) {
Response.Builder builder = cacheResponse.newBuilder();
if (ageMillis + minFreshMillis >= freshMillis) {
builder.addHeader("Warning", "110 HttpURLConnection \"Response is stale\"");
}
long oneDayMillis = 24 * 60 * 60 * 1000L;
if (ageMillis > oneDayMillis && isFreshnessLifetimeHeuristic()) {
builder.addHeader("Warning", "113 HttpURLConnection \"Heuristic expiration\"");
}
// 如果缓存没有过期并且需要缓存 那么 networkRequest = null cacheResponse = 缓存好的
return new CacheStrategy(null, builder.build());
}
// 本地有缓存,并且缓存已经过去,那么需要把上一次的请求头的一些字段带过去 If-Modified-Since
// 请求 -> 返回 -> 更新时间
// 请求(If-Modified-Since) -> 比对(304)
// Find a condition to add to the request. If the condition is satisfied, the response body
// will not be transmitted.
String conditionName;
String conditionValue;
if (etag != null) {
conditionName = "If-None-Match";
conditionValue = etag;
} else if (lastModified != null) {
conditionName = "If-Modified-Since";
conditionValue = lastModifiedString;
} else if (servedDate != null) {
conditionName = "If-Modified-Since";
conditionValue = servedDateString;
} else {
return new CacheStrategy(request, null); // No condition! Make a regular request.
}
Headers.Builder conditionalRequestHeaders = request.headers().newBuilder();
Internal.instance.addLenient(conditionalRequestHeaders, conditionName, conditionValue);
Request conditionalRequest = request.newBuilder()
.headers(conditionalRequestHeaders.build())
.build();
return new CacheStrategy(conditionalRequest, cacheResponse);
}
3.4 确定了缓存策略之后,再次回到CacheInterceptor
// 如果请求的 networkRequest 是空,缓存的 cacheResponse 是空我就返回 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();
}
3.5只从缓存中读取,并在请求网络
if (networkRequest == null) {
//在缓存策略中将本来不是空的request替换成了为空的networkRequest
//这样就不会再去请求网络了
// 如果缓存策略里面的 networkRequest 是空,那么就 返回 缓存好的 Response
return cacheResponse.newBuilder()
.cacheResponse(stripBody(cacheResponse))
.build();
}
3.6如果networkRequest这个之没有在CacheStratedgy中被缓存策略重置为null的话,说明缓存策略希望我们能够继续去请求网络
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());
}
}
3.7上面这个方法,将请求传递给下级拦截器继续请求网络的返回值可能是一个304等异常的网页,所以需要以下处理 如果是HTTP_NOT_MODIFIED(304) ,说明服务器端的数据没有发生过改变,我们依然可以读取缓存中的数据。
// 处理返回,处理 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());
}
}
3.8 要返回给上一级拦截器的响应
// 要返回 response
Response response = networkResponse.newBuilder()
.cacheResponse(stripBody(cacheResponse))
.networkResponse(stripBody(networkResponse))
.build();
3.9 将请求得到的响应缓存一份
if (cache != null) {
// 然后缓存获取的 Response
if (HttpHeaders.hasBody(response) && CacheStrategy.isCacheable(response, networkRequest)) {
// Offer this request to the cache.
CacheRequest cacheRequest = cache.put(response);
return cacheWritingResponse(cacheRequest, response);
}
if (HttpMethod.invalidatesCache(networkRequest.method())) {
try {
cache.remove(networkRequest);
} catch (IOException ignored) {
// The cache cannot be written.
}
}
}
4.ConnectInterceptor
newStream ——>findHealthyConnection() 首先判断有没有健康的,如果没有就创建(建立Socket,握手连接),连接缓存
得到一条结论: OkHttp 是基于原生的Socket
封装HttpCode 里面封装了 okio的Source(输入)和Sink(输出),我们通过HttpCode就可以操作Socket的输入输出,我们就可以向服务器写数据和读取返回数据。
4.1 在ConnectionInterceptor 的intercept方法
@Override public Response intercept(Chain chain) throws IOException {
RealInterceptorChain realChain = (RealInterceptorChain) chain;
Request request = realChain.request();
StreamAllocation streamAllocation = realChain.streamAllocation();
// We need the network to satisfy this request. Possibly for validating a conditional GET.
boolean doExtensiveHealthChecks = !request.method().equals("GET");
// newStream -> HttpCodec
HttpCodec httpCodec = streamAllocation.newStream(client, chain, doExtensiveHealthChecks);
// 拿到一个连接
RealConnection connection = streamAllocation.connection();
// 把这个连接传给下一级
return realChain.proceed(request, streamAllocation, httpCodec, connection);
}
4.1.1通过newStream()方法去找去实例化HttpCode这个封装了okio的接口
public HttpCodec newStream(
OkHttpClient client, Interceptor.Chain chain, boolean doExtensiveHealthChecks) {
int connectTimeout = chain.connectTimeoutMillis();
int readTimeout = chain.readTimeoutMillis();
int writeTimeout = chain.writeTimeoutMillis();
boolean connectionRetryEnabled = client.retryOnConnectionFailure();
try {
// 找一个连接,首先判断有没有健康的,没有就创建(建立Scoket,握手连接),连接缓存
RealConnection resultConnection = findHealthyConnection(connectTimeout, readTimeout,
writeTimeout, connectionRetryEnabled, doExtensiveHealthChecks);
// 封装 HttpCodec 里面封装了 okio 的 Source(输入) 和 Sink (输出)
HttpCodec resultCodec = resultConnection.newCodec(client, chain, this);
synchronized (connectionPool) {
codec = resultCodec;
return resultCodec;
}
} catch (IOException e) {
throw new RouteException(e);
}
}
4.1.2通过findHealthyConnection 去找一个健康的连接
private RealConnection findHealthyConnection(int connectTimeout, int readTimeout,
int writeTimeout, boolean connectionRetryEnabled, boolean doExtensiveHealthChecks)
throws IOException {
while (true) {
RealConnection candidate = findConnection(connectTimeout, readTimeout, writeTimeout,
connectionRetryEnabled);
// If this is a brand new connection, we can skip the extensive health checks.
synchronized (connectionPool) {
if (candidate.successCount == 0) {
return candidate;
}
}
// Do a (potentially slow) check to confirm that the pooled connection is still good. If it
// isn't, take it out of the pool and start again.
if (!candidate.isHealthy(doExtensiveHealthChecks)) {
noNewStreams();
continue;
}
return candidate;
}
}
4.1.3通过resultConnection.newCodec(client, chain, this);这个方法
public HttpCodec newCodec(OkHttpClient client, Interceptor.Chain chain,
StreamAllocation streamAllocation) throws SocketException {
if (http2Connection != null) {
return new Http2Codec(client, chain, streamAllocation, http2Connection);
} else {
socket.setSoTimeout(chain.readTimeoutMillis());
// Okio : 基于原生的IO的封装 ,IO涉及类和方法忒多,source(输入) sink(输出)
source.timeout().timeout(chain.readTimeoutMillis(), MILLISECONDS);
sink.timeout().timeout(chain.writeTimeoutMillis(), MILLISECONDS);
// Http1Codec 就是 封装了 source 和 sink 就是自己的输入输出流,本质就是操作 Socket 的输入输出流
return new Http1Codec(client, streamAllocation, source, sink);
}
}
在此之前 Socket和okio 进行了绑定
String maybeProtocol = connectionSpec.supportsTlsExtensions()
? Platform.get().getSelectedProtocol(sslSocket)
: null;
socket = sslSocket;
source = Okio.buffer(Okio.source(socket));
sink = Okio.buffer(Okio.sink(socket));
5.CallServerIntercepter
写数据和读取数据。
写头部信息
// 写一些请求头的数据
httpCodec.writeRequestHeaders(request);
realChain.eventListener().requestHeadersEnd(realChain.call(), request);
和表单
// 写数据,表单数据,文件
request.body().writeTo(bufferedRequestBody);
bufferedRequestBody.close();
realChain.eventListener()
6.连接的三个核心类
RealConnection ,
ConnectionPool,
StreamAlocation