OkHttp 是由 Square 发布的 HTTP Client,用于处理 HTTP 请求。
用官网的描述就是,An HTTP & HTTP/2 client for Android and Java applications.

优点

  • 支持 HTTP/2,多个连接可以共用一个 Socket
  • 连接池可以减少延迟(非 HTTP/2)
  • GZIP 压缩减少流量
  • Response 缓存
  • 重定向和重试

OkHttp 的用法

同步请求

需要在 AsyncTask 或者起线程来进行,调用execute()

1
2
3
4
5
6
7
8
9
10
11
12
private String doRequest(String param) {
Request.Builder builder = new Request.Builder();
builder.url(param);
Request request = builder.build();
try {
Response response = client.newCall(request).execute();
return response.body().string();
}catch (Exception e){
e.printStackTrace();
}
return null;
}

异步请求

调用enqueue()

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
OkHttpClient client = new OkHttpClient();

Request request = new Request.Builder()
.url(url)
.build();

client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
call.cancel();
}

@Override
public void onResponse(Call call, Response response) throws IOException {

final String myResponse = response.body().string();

MainActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
txtString.setText(myResponse);
}
});

}
}

设置 Header 和参数

在 URL 构建过程中通过addQueryParameter设置参数,在 Request 构建过程中设置 Header

1
2
3
4
5
6
7
8
9
HttpUrl.Builder urlBuilder = HttpUrl.parse("https://httpbin.org/get).newBuilder();
urlBuilder.addQueryParameter("website", "www.journaldev.com");
urlBuilder.addQueryParameter("tutorials", "android");
String url = urlBuilder.build().toString();

Request request = new Request.Builder()
.header("Authorization", "replace this text with your token")
.url(url)
.build();

post 请求

需要声明MediaType

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
public String postUrl= "https://reqres.in/api/users/";
public String postBody="{\n" +
" \"name\": \"morpheus\",\n" +
" \"job\": \"leader\"\n" +
"}";

public static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");

void postRequest(String postUrl,String postBody) throws IOException {

OkHttpClient client = new OkHttpClient();

RequestBody body = RequestBody.create(JSON, postBody);

Request request = new Request.Builder()
.url(postUrl)
.post(body)
.build();

client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
call.cancel();
}

@Override
public void onResponse(Call call, Response response) throws IOException {
Log.d("TAG",response.body().string());
}
});
}

设计思路

我认为 OkHttp 的核心是以分层的思想链式处理网络请求。所有处理的代码都位于XXXInterceptor中,一共有6个这样的 Interceptor,接口如下

1
2
3
public interface Interceptor {
Response intercept(Chain chain) throws IOException; // 处理当前层的请求
}

下图来源于 Piasy 的博客,很好地描述了 OkHttp 发送网络请求到处理完成的过程。

flow
flow

关键类讲解

  • RetryAndFollowUpInterceptor,处理请求失败重试以及重定向(30X)

  • BridgeInterceptor,对 Request 和 Response 进行封装,主要是写 Header,Gzip 解压缩等操作

  • CacheInterceptor,缓存,很棒的磁盘缓存设计,维护一个日志文件来进行缓存的恢复重建

  • ConnectInterceptor,管理与目标的连接,采用策略模式,有 HTTP(HTTP/1.1) 和 HTTP/2 两种策略,关键类StreamAllocation

  • CallServerInterceptor,数据交换,将数据传送给服务器,从服务器拉取数据。写请求头 -> 写请求体 -> 获取响应头 -> 获取响应体

设计模式

构建器模式

构建器模式可以减少冗长的构造函数,并且可以在设置参数时进行检查。OKHttpClient.java、Request.java 这些类里面都用到了 Builder 模式,简单写一个模版

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
public final class Foo {

final A a;

private Foo(Builder builder) {
this.a = builder.a;
}

public static class Builder {
private A a;

public Builder() {
this.a = "a";
}

public Builder a(A a) {
this.a = a;
return this;
}

public Foo build() {
return new Foo(this);
}
}
}

策略模式

策略模式体现面向接口编程的概念,将具体实现与接口剥离,减少耦合性。ContentInterceptor 里面的 HttpCodec 接口就是这样的,有 HTTP/1 和 HTTP/2 两种实现。

责任链模式(chain of responbility)

责任链模式包含了一系列对象,以及一系列处理指令。这些对象共同构成了一个链表,链表中的每一环都有一系列指令,链表中的对象经过逐级递归处理后,生成最终结果。可以向处理链的末尾添加新的处理指令。Interceptor.Chain 所采用的模式,每一层都处理各自的职责,按照链式递归调用。

小结

OkHttp 的代码复杂程度让人头大,我不敢说自己已经摸清了这个框架,有很多地方值得深入挖掘,比如基于日志 Cache 的实现细节,责任链模式的设计。下一课题:Retrofit。学习过程中参考了简书上“被代码淹没的小伙子”okhttp源码分析系列文章,感谢原作者。