Fork me on GitHub

OkHttp3(2)

举个栗子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
String url = "https://raw.github.com/square/okhttp/master/README.md";
OkHttpClient okHttpClient = new OkHttpClient();

Request request = new Request.Builder().url(url).build();
okhttp3.Response response = null;
okHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Log.i(TAG, "onFailure: ");
}

@Override
public void onResponse(Call call, Response response) throws IOException {
String json = response.body().string();
Log.i(TAG,json);
}
});

源码分析

new OkHttpClient()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
public OkHttpClient() {
//自动builder()
this(new Builder());
}

OkHttpClient(Builder builder) {
this.dispatcher = builder.dispatcher;
this.proxy = builder.proxy;
this.protocols = builder.protocols;
this.connectionSpecs = builder.connectionSpecs;
this.interceptors = Util.immutableList(builder.interceptors);
this.networkInterceptors = Util.immutableList(builder.networkInterceptors);
this.eventListenerFactory = builder.eventListenerFactory;
this.proxySelector = builder.proxySelector;
this.cookieJar = builder.cookieJar;
this.cache = builder.cache;
this.internalCache = builder.internalCache;
this.socketFactory = builder.socketFactory;

boolean isTLS = false;
for (ConnectionSpec spec : connectionSpecs) {
isTLS = isTLS || spec.isTls();
}

if (builder.sslSocketFactory != null || !isTLS) {
this.sslSocketFactory = builder.sslSocketFactory;
this.certificateChainCleaner = builder.certificateChainCleaner;
} else {
X509TrustManager trustManager = systemDefaultTrustManager();
this.sslSocketFactory = systemDefaultSslSocketFactory(trustManager);
this.certificateChainCleaner = CertificateChainCleaner.get(trustManager);
}

...

if (interceptors.contains(null)) {
throw new IllegalStateException("Null interceptor: " + interceptors);
}
if (networkInterceptors.contains(null)) {
throw new IllegalStateException("Null network interceptor: " + networkInterceptors);
}
}

new Request.Builder().url(url).build()

Builder()

1
2
3
4
public Builder() {
this.method = "GET";
this.headers = new Headers.Builder();
}

url()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public Builder url(String url) {
if (url == null) throw new NullPointerException("url == null");

// Silently replace web socket URLs with HTTP URLs.
if (url.regionMatches(true, 0, "ws:", 0, 3)) {
url = "http:" + url.substring(3);
} else if (url.regionMatches(true, 0, "wss:", 0, 4)) {
url = "https:" + url.substring(4);
}

HttpUrl parsed = HttpUrl.parse(url);
if (parsed == null) throw new IllegalArgumentException("unexpected url: " + url);
return url(parsed);
}

build()

1
2
3
4
public Request build() {
if (url == null) throw new IllegalStateException("url == null");
return new Request(this);
}

Request()

1
2
3
4
5
6
7
Request(Builder builder) {
this.url = builder.url;
this.method = builder.method;
this.headers = builder.headers.build();
this.body = builder.body;
this.tag = builder.tag != null ? builder.tag : this;
}

发起HTTP请求

okHttpClient.newCall(request)

1
2
3
@Override public Call newCall(Request request) {
return RealCall.newRealCall(this, request, false /* for web socket */);
}

根据请求创建新的Call,主要起作用的是newRealCall()

同步请求execute()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Override public Response execute() throws IOException {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
eventListener.callStart(this);
try {
client.dispatcher().executed(this);
Response result = getResponseWithInterceptorChain();
if (result == null) throw new IOException("Canceled");
return result;
} catch (IOException e) {
eventListener.callFailed(this, e);
throw e;
} finally {
client.dispatcher().finished(this);
}
}
  • 首先判断call是否执行过if (executed),每个call只能执行一次,如果还想要一样的call,可以通过clone()
1
2
3
4
@SuppressWarnings("CloneDoesntCallSuperClone") // We are a final type & this saves clearing state.
@Override public RealCall clone() {
return RealCall.newRealCall(client, originalRequest, forWebSocket);
}
  • client.dispatcher().executed(this);

执行call,HTTP请求的执行策略

  • getResponseWithInterceptorChain();

进行拦截操作,然后获得HTTP的返回结果

getResponseWithInterceptorChain源码分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
List<Interceptor> interceptors = new ArrayList<>();
interceptors.addAll(client.interceptors());
interceptors.add(retryAndFollowUpInterceptor);
interceptors.add(new BridgeInterceptor(client.cookieJar()));
interceptors.add(new CacheInterceptor(client.internalCache()));
interceptors.add(new ConnectInterceptor(client));
if (!forWebSocket) {
interceptors.addAll(client.networkInterceptors());
}
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. 设置拦截器集合List<Interceptor> interceptors = new ArrayList<>();
  2. 将配置client时候的拦截器加入集合interceptors.addAll(client.interceptors());
  3. 负责失败重试以及重定向interceptors.add(retryAndFollowUpInterceptor);
  4. 负责把用户构造的请求转换为发送到服务器的请求、把服务器返回的响应转换为用户友好的响应的interceptors.add(new BridgeInterceptor(client.cookieJar()));
  5. 负责读取缓存直接返回、更新缓存interceptors.add(new CacheInterceptor(client.internalCache()));
  6. 负责和服务器建立连接interceptors.add(new ConnectInterceptor(client));
  7. 配置OkHttpClient时设置的interceptors.addAll(client.networkInterceptors());
  8. 负责向服务器发送请求数据、从服务器读取响应数据interceptors.add(new CallServerInterceptor(forWebSocket));
  • client.dispatcher().finished(this);

通知dispatcher执行完毕

异步请求enqueue()

1
2
3
4
5
6
7
8
@Override public void enqueue(Callback responseCallback) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
eventListener.callStart(this);
client.dispatcher().enqueue(new AsyncCall(responseCallback));
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
  runningAsyncCalls.add(call);
  executorService().execute(call);
} else {
  readyAsyncCalls.add(call);
}

}

}
```

dispatcher在当前执行的时候如果还可以执行一个并发请求,那就立刻执行,否则加入runningAsyncCalls队列,等待当前请求执行完成,然后再执行。

其他的和同步请求一样。

获取返回数据

在发起网络请求之后,我们就可以在Response中获取到返回的数据,包括状态码、状态信息、返回头、responsebody,返回的responsebody可能会非常大,所以必须要用通过数据流的方式进行访问,其他部分可以随意获取。

responsebody需要注意:

  1. 每个body只能被消费一次,多次消费会报异常
  2. body必须被关闭,不然会发生泄漏

HTTP缓存

之前的拦截器中,提到了负责缓存拦截器,所以在建立连接之前,我们应该检查相应是否被缓存、缓存是否可以用,如果是就直接返回缓存的数据,否则进行后面的步骤将返回的网络数据写进缓存。

缓存的具体缓存逻辑是在OkHttp中内置封装类一个Cache类,利用DiskLruCache,按照LRU算法进行缓存淘汰。

总结

图源见水印