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); } });
} }
|
在 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 发送网络请求到处理完成的过程。
关键类讲解
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源码分析系列文章,感谢原作者。
最后更新时间:
本文系作者原创,如转载请注明出处。欢迎留言讨论,或通过邮件进行沟通~