游戏SDK架构设计之代码实现——网络框架
OKHttp 源码解析(一)
OKHttp 源码解析(二)拦截器
前言
目前大多数的网络框架都是使用 OKHttp ,Retrofit 也是基于 OKHttp,OKHttp 使用简单,但出现的问题不少,也借此机会了解一下 OKHttp 的源码。
本文的 OKHttp 源码基于 3.4.2 版本。
OKHttp 的官方文档:https://square.github.io/okhttp/
OKHttp 的基本使用流程
在 OKHttp 的源码入口就提示了如何简单实用 OKHttp:
OkHttpClient client = ...
// 创建 OkHttpClient
OkHttpClient clientWith30sTimeout = client.newBuilder()
.readTimeout(30, TimeUnit.SECONDS)
.build();
// 调用 newCall,传入请求体,execute执行任务
Response response = clientWith30sTimeout.newCall(request).execute();
1、OkHttpClient
类
OkHttpClient
采用建造者模式,通过 Builder 去配置初始化变量,没有配置的采用默认值。成员变量如下:
public Builder() {
// 调度器
dispatcher = new Dispatcher();
// 协议,默认的有 Protocol.HTTP_2, Protocol.SPDY_3, Protocol.HTTP_1_1
protocols = DEFAULT_PROTOCOLS;
proxySelector = ProxySelector.getDefault();
cookieJar = CookieJar.NO_COOKIES;
socketFactory = SocketFactory.getDefault();
connectionSpecs = DEFAULT_CONNECTION_SPECS;
//域名校验verifyAsIpAddress(host)? verifyIpAddress(host, certificate): verifyHostname(host, certificate)
// 会检验 IP 地址和域名,可以通过这个接口检验更多内容
hostnameVerifier = OkHostnameVerifier.INSTANCE;
certificatePinner = CertificatePinner.DEFAULT;
proxyAuthenticator = Authenticator.NONE;
// 身份验证器
authenticator = Authenticator.NONE;
//连接池,默认 5 个空闲链接,5分钟内不活动被释放
connectionPool = new ConnectionPool();
//DNS设置
dns = Dns.SYSTEM;
//是否从HTTP重定向到HTTPS
followSslRedirects = true;
//是否重定向
followRedirects = true;
//连接失败时是否重连,这个重连只有1次
retryOnConnectionFailure = true;
//连接超时,默认 10s
connectTimeout = 10_000;
//读取超时
readTimeout = 10_000;
//写入超时
writeTimeout = 10_000;
}
2、Request
类
这个类也是实用的建造者设计模式,构建请求体,成员变量比较简单。
// 请求地址
private HttpUrl url;
// 请求方式,GET(默认) 、POST、DELETE、PUT、PATCH、HEAD
private String method;
// 请求头,Headers 类来设置请求头内容
private Headers.Builder headers;
// 请求体,设置 contentType 和 请求参数
private RequestBody body;
// 标志,用来标志某个线程,可用于取消某个线程请求
private Object tag;
3、RealCall
请求调用接口
由调用 newCall
返回一个 RealCall
对象
/**
* Prepares the {@code request} to be executed at some point in the future.
*/
@Override public Call newCall(Request request) {
return new RealCall(this, request);
}
RealCall
实现了 Call
接口,可执行 execute
(同步请求) 、enqueue
(异步请求)、cancel
方法,是应用端和服务端的桥梁,展示应用端的请求和服务端返回的数据responseCallback
。
4、同步请求 execute
-
判断
Call
是否请求过,一个Call
只能执行一次,如果已经执行过则抛出异常。 -
调用
executed
方法将Call
添加到队列里。client.dispatcher().executed(this); // 将 Call 添加到队列里 synchronized void executed(RealCall call) { runningSyncCalls.add(call); } // 其中 runningSyncCalls /** Running asynchronous calls. Includes canceled calls that haven't finished yet. */ private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();
-
调用
getResponseWithInterceptorChain
构建拦截器链,遍历拦截器,执行请求,执行完成时返回结果。// 同步请求 try { // 调用 executed 方法将 Call 添加到队列里。 client.dispatcher().executed(this); // 调用 getResponseWithInterceptorChain 构建拦截器链 Response result = getResponseWithInterceptorChain(); if (result == null) throw new IOException("Canceled"); return result; } finally { // 将 Call 从队列中移除 client.dispatcher().finished(this); } private 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 (!retryAndFollowUpInterceptor.isForWebSocket()) { // 网络 interceptors.addAll(client.networkInterceptors()); } // 请求服务 interceptors.add(new CallServerInterceptor( retryAndFollowUpInterceptor.isForWebSocket())); // 创建拦截器链 Interceptor.Chain chain = new RealInterceptorChain( interceptors, null, null, null, 0, originalRequest); // 拦截器链执行结果 return chain.proceed(originalRequest); }
-
将
Call
从队列中移除client.dispatcher().finished(this);
5、异步请求,当执行异步任务时,由内部类 AsyncCall
实现,AsyncCall
就是一个 Runnable
对象。
执行步骤和同步任务差不多,都会先检查 Call 是否执行过,然后调用 getResponseWithInterceptorChain
构建拦截器链,遍历拦截器,执行请求,执行完成时返回结果。
拦截器的源码解析见下篇文章:
final class AsyncCall extends NamedRunnable {
// ...
@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);
}
}
}
6、Dispatcher
类
OKHttp 请求的调度器,内部维护了一个线程池和一些队列。
// 并行的最大请求数,有接口可修改
private int maxRequests = 64;
//每台主机同时执行的最大请求数
private int maxRequestsPerHost = 5;
// 线程池
private ExecutorService executorService;
public synchronized ExecutorService executorService() {
if (executorService == null) {
executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false));
}
return executorService;
}
// 队列
// 已经准备好的异步请求
private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();
// 正在运行的异步请求,包括已经取消的和运行未完成的
/** Running asynchronous calls. Includes canceled calls that haven't finished yet. */
private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();
/** Running synchronous calls. Includes canceled calls that haven't finished yet. */
private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();
OKHttp 的请求流程总结
OkHttpClient
通过newCall
访问RealCall
- 如果是同步请求,调用
execute
- 如果是异步请求,调用
enqueue
- 如果是同步请求,调用
- 以上都是通过
Dispatcher
将Call
添加到队列 - 调用
getResponseWithInterceptorChain
遍历拦截器,执行请求 - 获取结果
getResponse
- 将
Call
从 队列移除。