关于Okhttp3(三)--请求流程
前两两片我们介绍了,基本使用和如何查看源码,今天我们正式进入源码分析流程。流程图
首先我们先看一看它的请求流程,在Okhttp3中请求是基于拦截器原理,源代码如下:
源码路径:okhttp3/RealCall.java
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 |
// 开始执行整个请求 Response getResponseWithInterceptorChain() throws IOException { // Build a full stack of interceptors. // 拦截器栈 List |
整体框架图(图片来源网络,感谢作者):
通过上图,想必对Okhttp3的实现方式,已经有了基本的认识下面我们就一步一具体分析。
构造HttpClient
HttpClient采用了建造者设计模式来实例化。本身有多个字段用于全局对象,比去Cache、Dns等
- 静态代码块构造全局缓存
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
static { Internal.instance = new Internal() { // 略 @Override public void setCache(OkHttpClient.Builder builder, InternalCache internalCache) { // 写入缓存,指的是响应数据缓存 builder.setInternalCache(internalCache); }// 从缓存中获取有效的连接,仅支持Http/2, 本质就是从内存的ConnectiongPol中的Deque读取 @Override public RealConnection get( ConnectionPool pool, Address address, StreamAllocation streamAllocation) { return pool.get(address, streamAllocation); } // 将连接缓存到连接池中 @Override public void put(ConnectionPool pool, RealConnection connection) { pool.put(connection); }// 线路的缓存,多host多ip的青款 @Override public RouteDatabase routeDatabase(ConnectionPool connectionPool) { return connectionPool.routeDatabase; }// 略 }// 此处有很多种数据缓存处理,不了解并不影响代码分析,如有兴趣可自行研究
- Dispatcher, 分发请求,内部是有一个ThreadPoolExecutor
- Proxy, 代理连接,分三种类型直接(DIRECT)、Http(http)、SOCKS。
- ProxySelector,线路选择器,对应Okhttp的一大特点,自行线路选择,找到合适的连接
- Cache, 真正的缓存实现
- SSLSocketFactory, Https的支持
- ConnectionPool, 连接池
- Dns,dns解析(Java实现)
- 其他,如超时时间等
我们都知道一个请求有多部分组成,同样Okhttp3创建一个请求也要多部分。
- 构造请求头
- 构造请求体
- 发送一个请求
请求头
header并非每个请求都需要,要看与服务端是如何定义的,通常一个请求会默认一些头,比如Content-Type,Accept-Encoding,Connection等对应http协议Header本质上就是一个Map,只是在封装了一层而已,但是Okhttp3的实现不是这样,而是一个String数据,key + value的形式,即一个头占用数组的两位:
每一个色块对应一个header,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 |
// 源码路径 okhttp3/Headers.javapublic final class Headers { private final String[] namesAndValues; // 略 Builder addLenient(String name, String value) { namesAndValues.add(name); namesAndValues.add(value.trim()); return this; } // 略 } |
请求体有多种形式,对应的父类是RequestBody,有文件形式、Json等,MediaType决定了是何种形式,通常我们用的是FromBody和MultipartBody
- FromBody
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
public final class FormBody extends RequestBody { private static final MediaType CONTENT_TYPE = MediaType.parse("application/x-www-form-urlencoded"); private final List encodedNames; // 参数名称 private final List encodedValues; // 参数值 // 构造者 public static final class Builder { private final List names = new ArrayList<>(); private final List values = new ArrayList<>(); public Builder add(String name, String value) { names.add(HttpUrl.canonicalize(name, FORM_ENCODE_SET, false, false, true, true)); values.add(HttpUrl.canonicalize(value, FORM_ENCODE_SET, false, false, true, true)); return this; }//构造一个实例 public FormBody build() { return new FormBody(names, values); } } }
- MultipartBody
MultipartBody原理基本一致,区别在于他可以发送表单的同时也可以发送文件数据,再次不在赘述。
有了上面两个步骤,接下了就自然而让产生一个Request,顾名思义它就是对请求的封装,包括请求方式,请求头,请求体,请求路径等,源代码码也是比较简单,一看即明白。
1 2 3 4 5 6 7 |
public final class Request { final HttpUrl url; final String method; final Headers headers; final RequestBody body; final Object tag; } |
有了准备工作,现在我们就要发射了,Call是一个概念的封装,就像一列火车,蓄势待发,在铁轨停靠准备出发一样Call是一个接口,实现类只有一个RealCall,上面我们提到的流程就是在RealCall中。
1 2 3 4 5 6 7 8 9 10 11 12 |
public interface Call extends Cloneable { Request request(); // 获取请求封装的数据 Response execute() throws IOException; // 同步执行 void enqueue(Callback responseCallback); // 异步执行 void cancel(); // 取消请求 boolean isExecuted(); boolean isCanceled(); Call clone(); interface Factory { Call newCall(Request request); } } |
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 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 |
// 重点看看中文注释处即可 final class RealCall implements Call {final OkHttpClient client; // 重试拦截器 final RetryAndFollowUpInterceptor retryAndFollowUpInterceptor; /** The application's original request unadulterated by redirects or auth headers. */ final Request originalRequest; final boolean forWebSocket; // Guarded by this. private boolean executed; RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) { this.client = client; this.originalRequest = originalRequest; this.forWebSocket = forWebSocket; this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket); }@Override public Request request() { return originalRequest; }// 同步执行的实现 @Override public Response execute() throws IOException { // 一个call只能执行一次 synchronized (this) { if (executed) throw new IllegalStateException("Already Executed"); executed = true; } captureCallStackTrace(); try { // 将请求放在,请求池中执行,此处会立即执行 client.dispatcher().executed(this); // 获取结果,即执行多个链接器的调用链 Response result = getResponseWithInterceptorChain(); if (result == null) throw new IOException("Canceled"); return result; } finally { client.dispatcher().finished(this); } }private void captureCallStackTrace() { Object callStackTrace = Platform.get().getStackTraceForCloseable("response.body().close()"); retryAndFollowUpInterceptor.setCallStackTrace(callStackTrace); }//异步执行,不管行返回结果 @Override public void enqueue(Callback responseCallback) { synchronized (this) { if (executed) throw new IllegalStateException("Already Executed"); executed = true; } captureCallStackTrace(); // AsyncCall是一个Runnable的实现类,同时一个是RealCall的内部类 client.dispatcher().enqueue(new AsyncCall(responseCallback)); }@Override public void cancel() { retryAndFollowUpInterceptor.cancel(); }@Override public synchronized boolean isExecuted() { return executed; }@Override public boolean isCanceled() { return retryAndFollowUpInterceptor.isCanceled(); }@SuppressWarnings("CloneDoesntCallSuperClone") // We are a final type & this saves clearing state. @Override public RealCall clone() { return new RealCall(client, originalRequest, forWebSocket); }StreamAllocation streamAllocation() { return retryAndFollowUpInterceptor.streamAllocation(); }// 异步执行的线程封装,Android基本就是这里了 final class AsyncCall extends NamedRunnable { private final Callback responseCallback; AsyncCall(Callback responseCallback) { super("OkHttp %s", redactedUrl()); this.responseCallback = responseCallback; }String host() { return originalRequest.url().host(); }Request request() { return originalRequest; }RealCall get() { return RealCall.this; }@Override protected void execute() { boolean signalledCallback = false; try { // 执行调用链,是不是很重要,哈哈 Response response = getResponseWithInterceptorChain(); // 处理回掉 if (retryAndFollowUpInterceptor.isCanceled()) { 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! Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e); } else { responseCallback.onFailure(RealCall.this, e); } } finally { client.dispatcher().finished(this); } } }/** * Returns a string that describes this call. Doesn't include a full URL as that might contain * sensitive information. */ String toLoggableString() { return (isCanceled() ? "canceled " : "") + (forWebSocket ? "web socket" : "call") + " to " + redactedUrl(); }String redactedUrl() { return originalRequest.url().redact(); } // 最重要的入口了 // 最重要的入口了 // 最重要的入口了 // 重要事情说三遍 Response getResponseWithInterceptorChain() throws IOException { // Build a full stack of interceptors. List |
拦截器工作原理
Interceptor是一个接口,主要是对请求和响应的处理,而实现拦截器调用链的是其内部接口Chain
1 2 3 4 5 6 7 8 9 10 11 12 13 |
public interface Interceptor { // 管拦截 Response intercept(Chain chain) throws IOException; interface Chain { Request request(); // 管分发,前行 Response proceed(Request request) throws IOException; Connection connection(); } } |
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 43 44 45 46 47 48 |
// RealCall.getResponseWithInterceptorChain()中创建了一个实例 public final class RealInterceptorChain implements Interceptor.Chain { // RealCall.getResponseWithInterceptorChain()中已经赋值 private final Request request; private final List |
每一个RealInterceptorChain会对应一个Interceptor,然后Interceptor在产生下一个RealInterceptorChain,知道List迭代完成。
总结
【关于Okhttp3(三)--请求流程】Okhttp3的调用流程基本原理就是这样,重要的是思想,整个流程一气呵成,完全解耦。
推荐阅读
- 放屁有这三个特征的,请注意啦!这说明你的身体毒素太多
- 一个人的旅行,三亚
- 2018-02-06第三天|2018-02-06第三天 不能再了,反思到位就差改变
- 第三节|第三节 快乐和幸福(12)
- android第三方框架(五)ButterKnife
- 遇到一哭二闹三打滚的孩子,怎么办┃山伯教育
- 三十年后的广场舞大爷
- 一百二十三夜,请嫁给我
- 2018年9月5日,星期三,天气晴
- 即将到手三百万