@ZeroGeek
2018-06-13T02:14:56.000000Z
字数 4796
阅读 1621
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();@WorkerThreadprivate 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() {@Overridepublic void onFailure(Call call, IOException e) {}@Overridepublic 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