OKHttp真实调用请求的类是RealCall
Dispatcher该类是作为请求分发
//异步请求最多的请求个数
private int maxRequests = 64;
//同一个host最多异步请求的个数
private int maxRequestsPerHost = 5;
//线程池
private ExecutorService executorService;
//即将要请求的
private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();
//正在请求的
private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();
//同步请求
private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();
异步请求时如果最多异步请求超过64,并且同一主机请求个数超过了5就,放入到readyAsyncCalls
中
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
executorService().execute(call);
} else {
readyAsyncCalls.add(call);
}
}
当网络请求完毕之后会调用finish方法,从readyAsyncCalls
中把准备请求的拿出来
synchronized void finished(AsyncCall call) {
//将同步请求移除
if (!runningAsyncCalls.remove(call)) throw new AssertionError("AsyncCall wasn't running!");
//将readyAsyncCalls中等待的realCall放入线程池中
promoteCalls();
}
private void promoteCalls() {
if (runningAsyncCalls.size() >= maxRequests) return; // Already running max capacity.
if (readyAsyncCalls.isEmpty()) return; // No ready calls to promote.
for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
AsyncCall call = i.next();
if (runningCallsForHost(call) < maxRequestsPerHost) {
i.remove();
runningAsyncCalls.add(call);
executorService().execute(call);
}
if (runningAsyncCalls.size() >= maxRequests) return; // Reached max capacity.
}
}
同步请求时直接将RealCall放入到runningSyncCalls
中
synchronized void executed(RealCall call) {
runningSyncCalls.add(call);
}
拦截器
@Override protected void execute() {
boolean signalledCallback = false;
try {
Response response = getResponseWithInterceptorChain(forWebSocket);
if (canceled) {
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!
logger.log(Level.INFO, "Callback failure for " + toLoggableString(), e);
} else {
responseCallback.onFailure(RealCall.this, e);
}
} finally {
client.dispatcher().finished(this);
}
}
ApplicationInterceptorChain这是一个拦截器,用户可以自己定义拦截器进行拦截
如果没有拦截器,那么就可以进行网络请求了,在getResponse
方法中实例化了HttpEngine类
发送请求sendRequest
networkRequest
:只是设置了一些请求头的操作
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();
}
下面是缓存的策略,重点啊~
如果你的代码设置
File cacheFile = new File(context.getExternalCacheDir().toString(),"cache");
//缓存大小为10M
int cacheSize = 10 * 1024 * 1024;
//创建缓存对象
final Cache cache = new Cache(cacheFile,cacheSize);
OkHttpClient.Builder builder = new OkHttpClient.Builder()
.connectTimeout(mConnectTimeout, TimeUnit.SECONDS)
.readTimeout(mReadTimeOut, TimeUnit.SECONDS)
.writeTimeout(mWriteTimeOut, TimeUnit.SECONDS)
.cache(cache);
那么将会在访问网络之后
if (hasBody(userResponse)) {
maybeCache();
userResponse = unzip(cacheWritingResponse(storeRequest, userResponse));
}
将响应体写到Cache里面,采用LRU算法,Key是一个32位长度的MD5值,Value是文件封装的对象
当put存入之后,你下次responseCache.get
就是上一次的响应
InternalCache responseCache = Internal.instance.internalCache(client);
Response cacheCandidate = responseCache != null
? responseCache.get(request)
: null;
但是光拿到上一次的响应头还不算完,还得进行一些判断,目的是判断是否需要重新进行网络请求,因为可能响应头的资源已经过期,超出了规定的时间,就不能在用了,要重新进行网络请求
public Factory(long nowMillis, Request request, Response cacheResponse) {
//这个是当前系统的时间
this.nowMillis = nowMillis;
//请求
this.request = request;
//缓存中的响应
this.cacheResponse = cacheResponse;
if (cacheResponse != null) {
Headers headers = cacheResponse.headers();
for (int i = 0, size = headers.size(); i < size; i++) {
String fieldName = headers.name(i);
String value = headers.value(i);
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)) {
//首部字段Age能告知客户端,源服务器在多久前创建了响应,字段值的单位为秒。
//若创建该响应的服务器是缓存服务器,Age值是指缓存后的响应再次发起认证到认证
//完成的时间值
ageSeconds = HeaderParser.parseSeconds(value, -1);
} else if (OkHeaders.SENT_MILLIS.equalsIgnoreCase(fieldName)) {
//发送请求的本地时间。
sentRequestMillis = Long.parseLong(value);
} else if (OkHeaders.RECEIVED_MILLIS.equalsIgnoreCase(fieldName)) {
//收到响应的本地时间。
receivedResponseMillis = Long.parseLong(value);
}
}
}
}
只是对响应头进行了一些抽取,接下来
public CacheStrategy get() {
CacheStrategy candidate = getCandidate();
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;
}
重点先看下get
方法里面的getCandidate
方法,缓存策略的重点
private CacheStrategy getCandidate() {
// No cached response.
if (cacheResponse == null) {
//如果响应头是null,那么就得请求网络了
return new CacheStrategy(request, null);
}
//如果缺少必要的握手,则删除缓存的响应,也得去请求网络
if (request.isHttps() && cacheResponse.handshake() == null) {
return new CacheStrategy(request, null);
}
//主要是对各种状态进行检查
//这里面注意下这样代码
//!response.cacheControl().noStore() && !request.cacheControl().noStore();
//no-store这个响应字段含义:简单来说就是不能有缓存,应用于机密文件
if (!isCacheable(cacheResponse, request)) {
return new CacheStrategy(request, null);
}
//请求对象获取cacheControl对象,Request可以通过cacheControl方法进行设置
CacheControl requestCaching = request.cacheControl();
//requestCaching.noCache()是否需要缓存
//hasConditions(request)
//request.header("If-Modified-Since") != null || request.header("If-None-Match") != null
//If-Modified-Since和If-None-Match你可以理解成数据库的条件语句
//你想啊,有条件,证明每次请求都会不一样,那么当然需要重新请求网络了
//实在好奇就自己百度下吧
if (requestCaching.noCache() || hasConditions(request)) {
return new CacheStrategy(request, null);
}
//该方法里面有这样一句receivedAge + responseDuration + residentDuration
//就是现在的我距离上次发送请求的时间
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;
//我在自己的代码中加入了拦截器
/* class CacheInterceptor implements Interceptor{
@Override
public Response intercept(Chain chain) throws IOException {
Response originResponse = chain.proceed(chain.request());
//设置缓存时间为60秒,并移除了pragma消息头,移除它的原因是因为pragma也是控制缓存的一个消息头属性
return originResponse.newBuilder().removeHeader("pragma")
.header("Cache-Control","max-age=60").build();
}
}
*/
//这句话就是得到我设置缓存过期时间
CacheControl responseCaching = cacheResponse.cacheControl();
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\"");
}
return new CacheStrategy(null, builder.build());
}
Request.Builder conditionalRequestBuilder = request.newBuilder();
//为请求增加条件
if (etag != null) {
conditionalRequestBuilder.header("If-None-Match", etag);
} else if (lastModified != null) {
conditionalRequestBuilder.header("If-Modified-Since", lastModifiedString);
} else if (servedDate != null) {
conditionalRequestBuilder.header("If-Modified-Since", servedDateString);
}
//如果已经有条件了,那么就不能走缓存了,需要重新进行网络请求
Request conditionalRequest = conditionalRequestBuilder.build();
return hasConditions(conditionalRequest)
? new CacheStrategy(conditionalRequest, cacheResponse)
: new CacheStrategy(conditionalRequest, null);
}
以上就是缓存的策略
//假如你现在没有缓存,并且你还设置了CacheControl.FORCE_CACHE这个参数,那么你就会收
//到504的异常
if (candidate.networkRequest != null && request.cacheControl().onlyIfCached()) {
// We're forbidden from using the network and the cache is insufficient.
return new CacheStrategy(null, null);
}
回到上面接着说
if (responseCache != null) {
//记录当前请求是网络发起还是缓存发起
responseCache.trackResponse(cacheStrategy);
}
if (cacheCandidate != null && cacheResponse == null) {
closeQuietly(cacheCandidate.body()); // The cache candidate wasn't applicable. Close it.
}
//504错误
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;
}
//如果networkRequest为null那么就可以走缓存了,这种情况在前面讲过
if (networkRequest == null) {
userResponse = cacheResponse.newBuilder()
.request(userRequest)
.priorResponse(stripBody(priorResponse))
.cacheResponse(stripBody(cacheResponse))
.build();
userResponse = unzip(userResponse);
return;
}