@ZeroGeek
2018-06-13T02:14:56.000000Z
字数 4796
阅读 1493
Android
随着5G时代的即将到来,流量爆炸、短视频泛滥,底层网络编程的重要性不言而喻。OkHttp虽然已经被用烂了,但笔者秉承着知其所以然的心态来全面深入学习这个网络框架。希望通过该文章能让读者和笔者对网络框架的实现有深入的了解。
高效的HTTP框架
支持Android 2.3,要求JDK 1.7以上
SPDY(读作“SPeeDY”)是Google开发的基于TCP的应用层协议,用以最小化网络延迟,提升网络速度,优化用户的网络使用体验。SPDY并不是一种用于替代HTTP的协议,而是对HTTP协议的增强。新协议的功能包括数据流的多路复用、请求优先级以及HTTP报头压缩。谷歌表示,引入SPDY协议后,在实验室测试中页面加载速度比原先快64%。(摘自百度百科)
后面解读的源码基于3.10.0版本
Gradle依赖配置:
implementation 'com.squareup.okhttp3:okhttp:3.10.0'
OkHttpClient client = new OkHttpClient();
@WorkerThread
private String synchronousLoad(String url) throws IOException {
Request request = new Request.Builder()
.url(url)
.build();
Response response = client.newCall(request).execute();
return response.body().string();
}
private void asynchronousLoad(String url) {
Request request = new Request.Builder()
.url(url)
.build();
Call call = client.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
// 仍在子线程中
String result = response.body().string();
textView.setText(result);
}
});
}
当有多个连贯请求时,例如第三方登录通常有获取Token和服务器登录两个操作,若嵌套异步请求会降低代码可读性和可维护性,建议用同步请求,控制在子线程执行;如果是简单一个请求,则直接用异步请求即可。
public OkHttpClient() {
this(new Builder());
}
public Builder() {
dispatcher = new Dispatcher();
protocols = DEFAULT_PROTOCOLS;
connectionSpecs = DEFAULT_CONNECTION_SPECS;
eventListenerFactory = EventListener.factory(EventListener.NONE);
proxySelector = ProxySelector.getDefault();
cookieJar = CookieJar.NO_COOKIES;
socketFactory = SocketFactory.getDefault();
hostnameVerifier = OkHostnameVerifier.INSTANCE;
certificatePinner = CertificatePinner.DEFAULT;
proxyAuthenticator = Authenticator.NONE;
authenticator = Authenticator.NONE;
connectionPool = new ConnectionPool();
dns = Dns.SYSTEM;
followSslRedirects = true;
followRedirects = true;
retryOnConnectionFailure = true;
connectTimeout = 10_000;
readTimeout = 10_000;
writeTimeout = 10_000;
pingInterval = 0;
}
初始化参数:
部分代码如下:
public final class Request {
public static class Builder {
HttpUrl url;
String method;
Headers.Builder headers;
RequestBody body;
Object tag;
public Builder() {
this.method = "GET";
this.headers = new Headers.Builder();
}
// ...
}
}
需要设置四个参数:
一个真实的请求报文结构如下:
主要职能:
成员变量:
public final class Response implements Closeable {
final Request request;
final Protocol protocol;
final int code;
final String message;
final @Nullable Handshake handshake;
final Headers headers;
final @Nullable ResponseBody body;
final @Nullable Response networkResponse;
final @Nullable Response cacheResponse;
final @Nullable Response priorResponse;
final long sentRequestAtMillis;
final long receivedResponseAtMillis;
private volatile CacheControl cacheControl; // Lazily initialized.
// ...
}
对应响应报文:
这里对TLS 握手协议的记录。
TLS:Transport Layer Security(安全传输层协议)
TLS握手协议处理对等用户的认证,在这一层使用了公共密钥和证书,并协商算法和加密实际数据传输的密钥,该过程在TLS记录协议之上进行。TLS握手协议是TLS协议中最复杂的部分,它定义了10种消息,客户端和服务器利用这10种消息相互认证,协商哈希函数和加密算法并相互提供产生加密密钥的机密数据。TLS记录协议会在加密算法中用到这些加密密钥,从而提供数据保密性和一致性保护。(摘至百度百科)
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);
}
上面的内容如图所示:
重点看下proceed中的这段代码,是如何传递的。
@Override public Response proceed(Request request) throws IOException {
// ...
// Call the next interceptor in the chain.
RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
writeTimeout);
Interceptor interceptor = interceptors.get(index);
Response response = interceptor.intercept(next);
// ...
return response;
}
该类可以理解为拦截器的传输通道,所有的拦截处理都是在这个通道里完成,每次执行完一个拦截操作后,传递给下一个拦截器,直到所有的拦截器都处理完毕,由最后一个拦截器返回结果。
解析用户的请求,加工成最后的网络请求。
https://www.cnblogs.com/chenqf/p/6386163.html
为当前请求找到合适的连接,可能复用已有连接也可能是重新创建的连接,返回的连接由连接池负责决定。
向服务器发起真正的访问请求,并在接收到服务器返回后读取响应返回。
管理重用HTTP或者HTTP/2的连接,减少网络延迟。
https://blog.csdn.net/zhangliang_571/article/details/23508953