[关闭]
@ZeroGeek 2018-06-13T02:14:56.000000Z 字数 4796 阅读 1359

Android之OkHttp解读

Android


前言

随着5G时代的即将到来,流量爆炸、短视频泛滥,底层网络编程的重要性不言而喻。OkHttp虽然已经被用烂了,但笔者秉承着知其所以然的心态来全面深入学习这个网络框架。希望通过该文章能让读者和笔者对网络框架的实现有深入的了解。

基本介绍

高效的HTTP框架

基本使用

后面解读的源码基于3.10.0版本
Gradle依赖配置:
implementation 'com.squareup.okhttp3:okhttp:3.10.0'

同步请求

  1. OkHttpClient client = new OkHttpClient();
  2. @WorkerThread
  3. private String synchronousLoad(String url) throws IOException {
  4. Request request = new Request.Builder()
  5. .url(url)
  6. .build();
  7. Response response = client.newCall(request).execute();
  8. return response.body().string();
  9. }

异步请求

  1. private void asynchronousLoad(String url) {
  2. Request request = new Request.Builder()
  3. .url(url)
  4. .build();
  5. Call call = client.newCall(request);
  6. call.enqueue(new Callback() {
  7. @Override
  8. public void onFailure(Call call, IOException e) {
  9. }
  10. @Override
  11. public void onResponse(Call call, Response response) throws IOException {
  12. // 仍在子线程中
  13. String result = response.body().string();
  14. textView.setText(result);
  15. }
  16. });
  17. }

当有多个连贯请求时,例如第三方登录通常有获取Token和服务器登录两个操作,若嵌套异步请求会降低代码可读性和可维护性,建议用同步请求,控制在子线程执行;如果是简单一个请求,则直接用异步请求即可。

整体流程梳理

流程

  1. 创建OkHttpClient
  2. 构建请求,添加url,设置类型、参数
  3. 将请求加入到线程池中或者同步执行
  4. 处理结果并返回

类讲解

OkHttpClient

  1. public OkHttpClient() {
  2. this(new Builder());
  3. }
  4. public Builder() {
  5. dispatcher = new Dispatcher();
  6. protocols = DEFAULT_PROTOCOLS;
  7. connectionSpecs = DEFAULT_CONNECTION_SPECS;
  8. eventListenerFactory = EventListener.factory(EventListener.NONE);
  9. proxySelector = ProxySelector.getDefault();
  10. cookieJar = CookieJar.NO_COOKIES;
  11. socketFactory = SocketFactory.getDefault();
  12. hostnameVerifier = OkHostnameVerifier.INSTANCE;
  13. certificatePinner = CertificatePinner.DEFAULT;
  14. proxyAuthenticator = Authenticator.NONE;
  15. authenticator = Authenticator.NONE;
  16. connectionPool = new ConnectionPool();
  17. dns = Dns.SYSTEM;
  18. followSslRedirects = true;
  19. followRedirects = true;
  20. retryOnConnectionFailure = true;
  21. connectTimeout = 10_000;
  22. readTimeout = 10_000;
  23. writeTimeout = 10_000;
  24. pingInterval = 0;
  25. }

初始化参数:

Request

部分代码如下:

  1. public final class Request {
  2. public static class Builder {
  3. HttpUrl url;
  4. String method;
  5. Headers.Builder headers;
  6. RequestBody body;
  7. Object tag;
  8. public Builder() {
  9. this.method = "GET";
  10. this.headers = new Headers.Builder();
  11. }
  12. // ...
  13. }
  14. }

需要设置四个参数:

一个真实的请求报文结构如下:

RealCall

主要职能:

Response

成员变量:

  1. public final class Response implements Closeable {
  2. final Request request;
  3. final Protocol protocol;
  4. final int code;
  5. final String message;
  6. final @Nullable Handshake handshake;
  7. final Headers headers;
  8. final @Nullable ResponseBody body;
  9. final @Nullable Response networkResponse;
  10. final @Nullable Response cacheResponse;
  11. final @Nullable Response priorResponse;
  12. final long sentRequestAtMillis;
  13. final long receivedResponseAtMillis;
  14. private volatile CacheControl cacheControl; // Lazily initialized.
  15. // ...
  16. }

对应响应报文:

Protocol,支持的协议:

Handshake

这里对TLS 握手协议的记录。

TLS:Transport Layer Security(安全传输层协议)

TLS握手协议处理对等用户的认证,在这一层使用了公共密钥和证书,并协商算法和加密实际数据传输的密钥,该过程在TLS记录协议之上进行。TLS握手协议是TLS协议中最复杂的部分,它定义了10种消息,客户端和服务器利用这10种消息相互认证,协商哈希函数和加密算法并相互提供产生加密密钥的机密数据。TLS记录协议会在加密算法中用到这些加密密钥,从而提供数据保密性和一致性保护。(摘至百度百科)

核心-拦截器与链式调用

  1. Response getResponseWithInterceptorChain() throws IOException {
  2. // Build a full stack of interceptors.
  3. List<Interceptor> interceptors = new ArrayList<>();
  4. interceptors.addAll(client.interceptors());
  5. interceptors.add(retryAndFollowUpInterceptor);
  6. interceptors.add(new BridgeInterceptor(client.cookieJar()));
  7. interceptors.add(new CacheInterceptor(client.internalCache()));
  8. interceptors.add(new ConnectInterceptor(client));
  9. if (!forWebSocket) {
  10. interceptors.addAll(client.networkInterceptors());
  11. }
  12. interceptors.add(new CallServerInterceptor(forWebSocket));
  13. Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
  14. originalRequest, this, eventListener, client.connectTimeoutMillis(),
  15. client.readTimeoutMillis(), client.writeTimeoutMillis());
  16. return chain.proceed(originalRequest);
  17. }

上面的内容如图所示:

流程

总体概述,责任链模式

RealInterceptorChain

重点看下proceed中的这段代码,是如何传递的。

  1. @Override public Response proceed(Request request) throws IOException {
  2. // ...
  3. // Call the next interceptor in the chain.
  4. RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
  5. connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
  6. writeTimeout);
  7. Interceptor interceptor = interceptors.get(index);
  8. Response response = interceptor.intercept(next);
  9. // ...
  10. return response;
  11. }

该类可以理解为拦截器的传输通道,所有的拦截处理都是在这个通道里完成,每次执行完一个拦截操作后,传递给下一个拦截器,直到所有的拦截器都处理完毕,由最后一个拦截器返回结果。

RetryAndFollowUpInterceptor

BridgeInterceptor

解析用户的请求,加工成最后的网络请求。

CacheInterceptor

https://www.cnblogs.com/chenqf/p/6386163.html

ConnectInterceptor

为当前请求找到合适的连接,可能复用已有连接也可能是重新创建的连接,返回的连接由连接池负责决定。

CallServerInterceptor

向服务器发起真正的访问请求,并在接收到服务器返回后读取响应返回。

ConnectionPool

管理重用HTTP或者HTTP/2的连接,减少网络延迟。

推荐阅读

https://blog.csdn.net/zhangliang_571/article/details/23508953

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注