读源码之Okhttp3.x

定义个人解读

OkHttp is HTTP client for Java and Kotlin.

定义其一是说OKHttp是为JavaKotlin(4.x版本已经用Kotlin重写)平台打造的高效网络框架,自不必多说;其二OkHttp是Http 客户端,这里面包含的知识就很多了:

  • 专注于Http协议,不适用于其他协议;专注于客户端Http通信需求,不适用于服务端。

  • 支持所有的Http协议版本,意味着支持所有的Http协议通信。OkHttp帮我们关注了Http世界动态,HTML5新协议WebSocket同样支持。

注 文章参考版本 ‘3.14.7’ 不再支持 http/1.0 和 SPDY_3。

HTTP_1_0(“http/1.0”)

HTTP_1_1(“http/1.1”)

SPDY_3(“spdy/3.1”)

HTTP_2(“h2”)

H2_PRIOR_KNOWLEDGE(“h2_prior_knowledge”)

QUIC(“quic”)

  • 支持多种SSL/TLS版本,意味Https也不在话下。

TLS_1_3(“TLSv1.3”), // 2016.

TLS_1_2(“TLSv1.2”), // 2008

TLS_1_1(“TLSv1.1”), // 2006

TLS_1_0(“TLSv1”), // 1999

SSL_3_0(“SSLv3”), // 1996

我个人觉得,OkHttp可以理解为一个小型浏览器(除去界面渲染功能),在地址栏输入URL到返回结果,中间过程涉及很多动作,如缓存、延迟、安全验证、连接、DNS解析、cookie等等。OkHttp能够做到使用它好比像普通用户使用浏览器一样简单,真是很了不起。所以OkHttp不仅仅是一个框架而已,更是Http协议甚至是TCP/IP协议的最佳实战基地。理解它,个人觉得需要扎实的网络协议基础知识,
推荐一个书单:
在这里插入图片描述

顺便提一下,Okhttp 整个工程除去test代码,实际不到3万代码,相当于一个中等规模的APP。

六个问题读源码

首先看一下OKhttp的大致流程:

在这里插入图片描述

对网络进行配置有两个地方,一是OKHttpClient全局配置(自定义Interceptor等),二是Request配置(缓存策略等)使不同Request可以具有不同策略。

OkHttpClient配置:

public Builder() {
  dispatcher = new Dispatcher();//异步Call执行调度
  protocols = DEFAULT_PROTOCOLS;//Http 协议
  connectionSpecs = DEFAULT_CONNECTION_SPECS;// SSL/TLS 配置
  eventListenerFactory = EventListener.factory(EventListener.NONE);//Events 事件
  proxySelector = ProxySelector.getDefault();// 代理
  if (proxySelector == null) {
    proxySelector = new NullProxySelector();
  }
  cookieJar = CookieJar.NO_COOKIES;// Cookie 配置
  socketFactory = SocketFactory.getDefault();//Socket 构造工厂
  hostnameVerifier = OkHostnameVerifier.INSTANCE;
  certificatePinner = CertificatePinner.DEFAULT;
  proxyAuthenticator = Authenticator.NONE;
  authenticator = Authenticator.NONE;
  connectionPool = new ConnectionPool();// 连接池
  dns = Dns.SYSTEM;
  followSslRedirects = true;
  followRedirects = true;
  retryOnConnectionFailure = true;
  callTimeout = 0;
  connectTimeout = 10_000;
  readTimeout = 10_000;
  writeTimeout = 10_000;
  pingInterval = 0;
}

Request配置:

Builder(Request request) {
  this.url = request.url;//请求URL
  this.method = request.method;//Http 方法
  this.body = request.body;// Http 请求体
  this.tags = request.tags.isEmpty()
      ? Collections.emptyMap()
      : new LinkedHashMap<>(request.tags);//Tag标记
  this.headers = request.headers.newBuilder();// Http请求头
}

Interceptor链

在这里插入图片描述

Application Interceptor 和 NetworkInterceptor的区别一目了然:一个参与RetryAndFollowUpInterceptor 重试和重定向循环,一个不参与,且为第一个拦截器,只对最终response起作用。

  List<Interceptor> interceptors = new ArrayList<>();
  // 添加自定义Application Interceptor 
  interceptors.addAll(client.interceptors());
  interceptors.add(new RetryAndFollowUpInterceptor(client));
  interceptors.add(new BridgeInterceptor(client.cookieJar()));
  interceptors.add(new CacheInterceptor(client.internalCache()));
  interceptors.add(new ConnectInterceptor(client));
  // 添加自定义NetworkInterceptor,如果为WebSocket链接,自定义NetworkInterceptor无法起作用
  if (!forWebSocket) {
    interceptors.addAll(client.networkInterceptors());
  }
  interceptors.add(new CallServerInterceptor(forWebSocket));

上述代码显示了Interceptors的前后顺序,值得注意一点的是,如果是WebSocket链接,自定义NetworkInterceptor将无法起作用。关于各个Interceptor的源码详解,其他Blog写的特别棒,大伙自行查询。

这里说一下ConnectInterceptor的ConnectionPool(连接池)。ConnectionPool是对Connection对象的管理,属于对象池。

Background threads are used to cleanup expired connections. There will be at most a single thread running per connection pool. The thread pool executor permits the pool itself to be garbage collected.

一:后台线程主要作用是garbage collected(垃圾回收);二:最多只有一个线程。
在这里插入图片描述

自定义Interceptor以及LoggingInterceptor打印的是什么

通过上文,理解两种自定义Interceptor的关键是其在Interceptor链中的位置。每种Interceptor拦截处理以Chain.process()方法为分水岭,之前可以对Request进行拦截,之后对Response拦截,只有调用Chain.process方法才会进行下一个拦截器处理。Application Interceptor 处于Interceptor链第一个且不参与重试和重定向,所以只关心最后的response,并且有权利去决定是否使用Okhttp默认Interceptor,当然如果不使用而是重写Interceptor链,Okhttp也没有必要引用。NetWork Interceptor处于客户端与服务端建立链接和通信之间,且参与重试和重定向,所以可以得到更多Request头部以及网络链接过程信息。LoggingInterceptor打印的是什么,答案不言自明。根据自己想要的信息,将LoggingInterceptor放置在Interceptor链中的相应位置。

如何配置协议

默认协议配置DEFAULT_PROTOCOLS = Util.immutableList(Protocol.HTTP_2, Protocol.HTTP_1_1);

协议配置代码:

    public Builder protocols(List<Protocol> protocols) {
      protocols = new ArrayList<>(protocols);
      // H2_PRIOR_KNOWLEDGE 和 HTTP_1_1必须配置其一。
      if (!protocols.contains(Protocol.H2_PRIOR_KNOWLEDGE)
          && !protocols.contains(Protocol.HTTP_1_1)) {
        throw new IllegalArgumentException(
            "protocols must contain h2_prior_knowledge or http/1.1: " + protocols);
      }

      // 如果配置H2_PRIOR_KNOWLEDGE,不在允许配置其他协议版本。
      if (protocols.contains(Protocol.H2_PRIOR_KNOWLEDGE) && protocols.size() > 1) {
        throw new IllegalArgumentException(
            "protocols containing h2_prior_knowledge cannot use other protocols: " + protocols);
      }
      // 不再支持HTTP_1_0
      if (protocols.contains(Protocol.HTTP_1_0)) {
        throw new IllegalArgumentException("protocols must not contain http/1.0: " + protocols);
      }
      if (protocols.contains(null)) {
        throw new IllegalArgumentException("protocols must not contain null");
      }
      // 不再支持SPDY_3
      protocols.remove(Protocol.SPDY_3);
      this.protocols = Collections.unmodifiableList(protocols);
      return this;
    }

有一点需要说明的是H2_PRIOR_KNOWLEDGE是不能和Https一起使用的。

// RealConnection.connect方法
if (route.address().protocols().contains(Protocol.H2_PRIOR_KNOWLEDGE)) {
  throw new RouteException(new UnknownServiceException(
      "H2_PRIOR_KNOWLEDGE cannot be used with HTTPS"));
}

缓存怎么用

缓存策略配置是在Request端,所以不同Request可以具有不同的缓存策略。

另外,Cache类为缓存仓库,负责存入与取出;CacheStrategy类仓库管理者,负责缓存策略门卡检验。

  // CacheInterceptor.intercept方法
  CacheStrategy strategy = new CacheStrategy.Factory(now, chain.request(), cacheCandidate).get();
Request request = new Request.Builder()
      .url(url)
      //noCache(): 就算是本地有缓存,也不会读缓存,直接访问服务器
      //noStore(): 不会缓存数据,直接访问服务器
      //onlyIfCached():只请求缓存中的数据,不靠谱
      .cacheControl(new CacheControl.Builder().build())
      .build();

非常棒的一篇Blog,https://blog.csdn.net/briblue/article/details/52920531

Https如何配置

官方代码示例,https://square.github.io/okhttp/https/

Event事件机制

官方代码示例,https://square.github.io/okhttp/events

Help

资源

如需文章中书籍与视频资源,@邮箱zhckogx@163.com

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值