https://futurestud.io/tutorials/retrofit-getting-started-and-android-client
class Request
{
private final HttpUrl url;
private final String method;
private final Headers headers;
private final RequestBody body;
private final Object tag;
private volatile URI javaNetUri; // Lazily initialized.
private volatile CacheControl cacheControl; // Lazily initialized.
public CacheControl cacheControl() {
CacheControl result = cacheControl;//这里Request中的cacheControl为null
return result != null ? result : (cacheControl = CacheControl.parse(headers));//执行cacheControl = CacheControl.parse(headers)
}
}
class OkHttpClient extends Call.Factory
{
dispatcher = new Dispatcher();
protocols = DEFAULT_PROTOCOLS;
connectionSpecs = DEFAULT_CONNECTION_SPECS;
proxySelector = ProxySelector.getDefault();
cookieJar = CookieJar.NO_COOKIES;
socketFactory = SocketFactory.getDefault();
hostnameVerifier = OkHostnameVerifier.INSTANCE;
certificatePinner = CertificatePinner.DEFAULT;
proxyAuthenticator = Authenticator.NONE;
authenticator = Authenticator.NONE;
connectionPool = new ConnectionPool();
dns = Dns.SYSTEM;
followSslRedirects = true;
followRedirects = true;
retryOnConnectionFailure = true;
connectTimeout = 10_000;
readTimeout = 10_000;
writeTimeout = 10_000;
@Override
public Call newCall(Request request) {
return new RealCall(this, request);
}
}
class RealCall extends Call
{
private final OkHttpClient client;
// Guarded by this.
private boolean executed;
volatile boolean canceled;
/** The application's original request unadulterated by redirects or auth headers. */
Request originalRequest;
HttpEngine engine;
@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);
}
}
private Response getResponseWithInterceptorChain(boolean forWebSocket) throws IOException {
Interceptor.Chain chain = new ApplicationInterceptorChain(0, originalRequest, forWebSocket);
return chain.proceed(originalRequest);
}
class 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);
}
}
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(), 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, 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;
}
request = followUp;
engine = new HttpEngine(client, request, false, false, forWebSocket, streamAllocation, null,
response);
}
}
}
class Dispatcher
{
/** Running synchronous calls. Includes canceled calls that haven't finished yet. */
private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();
/** Used by {@code Call#execute} to signal it is in-flight. */
synchronized void executed(RealCall call) {
runningSyncCalls.add(call);
}
}
class HttpEngine
{
public final StreamAllocation streamAllocation;
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;
}
public void sendRequest() throws RequestException, RouteException, IOException {
if (cacheStrategy != null) return; // Already sent.
if (httpStream != null) throw new IllegalStateException();
Request request = networkRequest(userRequest);// 1为用户创建的Request添加一些必要的请求头
InternalCache responseCache = Internal.instance.internalCache(client);//这里的Internal对象只在OkhttpClient中被实现,这里返回OkhttpClient中的internalCache为null
Response cacheCandidate = responseCache != null
? responseCache.get(request)
: null;//responseCache为null,所以这里也为null
long now = System.currentTimeMillis();//当前毫秒
cacheStrategy = new CacheStrategy.Factory(now, request, cacheCandidate).get();//没啥操作
networkRequest = cacheStrategy.networkRequest;//这里为上面的request
cacheResponse = cacheStrategy.cacheResponse;//null
if (responseCache != null) {//跳过
responseCache.trackResponse(cacheStrategy);
}
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.
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 = 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 {
httpStream = connect();
httpStream.setHttpEngine(this);
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 HttpStream connect() throws RouteException, RequestException, IOException {
boolean doExtensiveHealthChecks = !networkRequest.method().equals("GET");//请求是否为!Get方法
return streamAllocation.newStream(client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis(),
client.retryOnConnectionFailure(), doExtensiveHealthChecks);
}
}
class CahceStrategy
{
/** The request to send on the network, or null if this call doesn't use the network. */
public final Request networkRequest;
/** The cached response to return or validate; or null if this call doesn't use a cache. */
public final Response cacheResponse;
private CacheStrategy(Request networkRequest, Response cacheResponse) {
this.networkRequest = networkRequest;
this.cacheResponse = cacheResponse;
}
class Factory
{
public Factory(long nowMillis, Request request, Response cacheResponse) {
this.nowMillis = nowMillis;
this.request = request;
this.cacheResponse = cacheResponse;
...
}
public CacheStrategy get() {
CacheStrategy candidate = getCandidate();
if (candidate.networkRequest != null && request.cacheControl().onlyIfCached()) {//onlyIfCached()为false,将不会执行里面
// We're forbidden from using the network and the cache is insufficient.
return new CacheStrategy(null, null);
}
return candidate;
}
private CacheStrategy getCandidate() {
// No cached response.
if (cacheResponse == null) {
return new CacheStrategy(request, null);
}
...
}
}
}
class CacheControl
{
public static CacheControl parse(Headers headers) {
boolean noCache = false;
boolean noStore = false;
int maxAgeSeconds = -1;
int sMaxAgeSeconds = -1;
boolean isPrivate = false;
boolean isPublic = false;
boolean mustRevalidate = false;
int maxStaleSeconds = -1;
int minFreshSeconds = -1;
boolean onlyIfCached = false;
boolean noTransform = false;
boolean canUseHeaderValue = true;
String headerValue = null;
for (int i = 0, size = headers.size(); i < size; i++) {
String name = headers.name(i);
String value = headers.value(i);
if (name.equalsIgnoreCase("Cache-Control")) {//heards中没有
if (headerValue != null) {
// Multiple cache-control headers means we can't use the raw value.
canUseHeaderValue = false;
} else {
headerValue = value;
}
} else if (name.equalsIgnoreCase("Pragma")) {//heards中没有
// Might specify additional cache-control params. We invalidate just in case.
canUseHeaderValue = false;
} else {
continue;
}
int pos = 0;
while (pos < value.length()) {
int tokenStart = pos;
pos = HeaderParser.skipUntil(value, pos, "=,;");
String directive = value.substring(tokenStart, pos).trim();
String parameter;
if (pos == value.length() || value.charAt(pos) == ',' || value.charAt(pos) == ';') {
pos++; // consume ',' or ';' (if necessary)
parameter = null;
} else {
pos++; // consume '='
pos = HeaderParser.skipWhitespace(value, pos);
// quoted string
if (pos < value.length() && value.charAt(pos) == '\"') {
pos++; // consume '"' open quote
int parameterStart = pos;
pos = HeaderParser.skipUntil(value, pos, "\"");
parameter = value.substring(parameterStart, pos);
pos++; // consume '"' close quote (if necessary)
// unquoted string
} else {
int parameterStart = pos;
pos = HeaderParser.skipUntil(value, pos, ",;");
parameter = value.substring(parameterStart, pos).trim();
}
}
if ("no-cache".equalsIgnoreCase(directive)) {
noCache = true;
} else if ("no-store".equalsIgnoreCase(directive)) {
noStore = true;
} else if ("max-age".equalsIgnoreCase(directive)) {
maxAgeSeconds = HeaderParser.parseSeconds(parameter, -1);
} else if ("s-maxage".equalsIgnoreCase(directive)) {
sMaxAgeSeconds = HeaderParser.parseSeconds(parameter, -1);
} else if ("private".equalsIgnoreCase(directive)) {
isPrivate = true;
} else if ("public".equalsIgnoreCase(directive)) {
isPublic = true;
} else if ("must-revalidate".equalsIgnoreCase(directive)) {
mustRevalidate = true;
} else if ("max-stale".equalsIgnoreCase(directive)) {
maxStaleSeconds = HeaderParser.parseSeconds(parameter, Integer.MAX_VALUE);
} else if ("min-fresh".equalsIgnoreCase(directive)) {
minFreshSeconds = HeaderParser.parseSeconds(parameter, -1);
} else if ("only-if-cached".equalsIgnoreCase(directive)) {
onlyIfCached = true;
} else if ("no-transform".equalsIgnoreCase(directive)) {
noTransform = true;
}
}
}
if (!canUseHeaderValue) {//canUseHeaderValue为true
headerValue = null;
}
return new CacheControl(noCache, noStore, maxAgeSeconds, sMaxAgeSeconds, isPrivate, isPublic,
mustRevalidate, maxStaleSeconds, minFreshSeconds, onlyIfCached, noTransform, headerValue);//这里的onlyIfCached为false
}
}
网友评论