OKhttp网络库分析

840 阅读4分钟

总述

最近在学习网络相关的知识,在熟悉基础的网络知识后,今天复习一下经常用的网络请求库Okhttp的基本使用

使用和调用流程

首先我们查看文档其的基本使用,然后根据基本使用,分析其调用流程

基本使用

//创建client
OkHttpClient client = new OkHttpClient();

 //构建请求
 Request request = new Request.Builder()
      .url(url)
      .build();
//执行请求,等待返回结果
Response response = client.newCall(request).execute()

基本流程

okhttp请求执行流程.png

核心类分析

简述

根据上面的流程,我们可以得到执行一次请求所使用到的核心类.它们分别是

  • OkhttpClient
  • ConnectionPool
  • Request
  • RealCall,AsyncCall
  • Response
  • RetryAndFollowUpInterceptor
  • BridgeInterceptor
  • CacheInterceptor
  • ConnectInterceptor
  • CallServerInterceptor
  • RealInterceptorChain

OkhttpClient中的参数

  1. DEFAULT_PROTOCOLS =Util.immutableList( Protocol.HTTP_2, Protocol.HTTP_1_1)
  • 连接的协议,Http2,Http1.1
  • Protocol类里面是各种协议的定义,还有Http1.0,Quic
  1. DEFAULT_CONNECTION_SPECS = Util.immutableList( ConnectionSpec.MODERN_TLS, ConnectionSpec.CLEARTEXT);
  • 传输加密算法设置,TLS,CLEARTEXT(不加密)
  1. ==Dispatcher==
  • 异步请求时的配置策略
  • 最大请求数64
  • 默认同一个主机,最大为5
  • 负责异步任务的分发
  • 使用Executroservice,创建线程,进行网络请求
new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
          new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false));
  • 三个队列维护请求任务
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<>();
  • 异步请求加入是使用
//RealCall
@Override public void enqueue(Callback responseCallback) {
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    captureCallStackTrace();
    eventListener.callStart(this);
    client.dispatcher().enqueue(new AsyncCall(responseCallback));
  }

  1. proxy
  • 网络请求代理的设置
  • 有三种类型,Direct,http;sock5
  1. protocols集合,跟默认的协议一样,这里可以自己配置
  2. List connectionSpecs 连接加密算法,也与上面默认配置一样
  3. interceptors 自定义拦截器集合
  4. networkInterceptors 网络拦截器
  • 当设置forwebsocket 为false时,使用
if (!forWebSocket) {
      interceptors.addAll(client.networkInterceptors());
    }
  1. eventListenerFactory:网络请求过程事件监听器的创建工厂类
callStart;callEnd;responseBodyEnd;等
  1. ProxySelector 代理服务选择类
  2. CookieJar:http coookie策略
  • 配置保存http cookie的策略
  • 实现类ReactCookieJarContainer
@Override
  public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {
    if (cookieJar != null) {
      cookieJar.saveFromResponse(url, cookies);
    }
  }
  1. cache
  • 缓存http和https的响应到文件系统,节省宽带,进行复用
Request request = new Request.Builder()
        .cacheControl(new CacheControl.Builder()
        .maxAge(0, TimeUnit.SECONDS)
        .build())
        .url("http://publicobject.com/helloworld.txt")
       .build();
  • 针对get和put请求
  • 内部使用DiskLruCache缓存类进行控制
  1. internalCache:Cache的内部类,内部调用Cache的方法,
  • 如果设置setChache,就会将其置空,两个只能存在一个
  1. socketFactory:创建socket
  2. sslSocketFactory:创建sslSocket,
  • 这个需要自己实现,默认的工厂类都是抛出异常DefaultSSLSocketFactory
  1. certificateChainCleaner
  • Computes the effective certificate chain from the raw array returned by Java's built in TLS APIs
  1. hostnameVerifier--》OkHostnameVerifier
  • 主机地址校验,用于自签名证书使用
  1. certificatePinner
  • https证书;锁定证书可以防止对证书颁发机构相关的攻击
  • Pinning是每个主机名和/或每个通配符模式。要同时使用publicobject.com和www.publicobject.com,必须配置这两个主机名。
String hostname = "publicobject.com";
 CertificatePinner certificatePinner = new CertificatePinner.Builder()
        .add(hostname, "sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=")
          .build();
      OkHttpClient client = OkHttpClient.Builder()
          .certificatePinner(certificatePinner)
          .build();
 
      Request request = new Request.Builder()
          .url("https://" + hostname)
          .build();
      client.newCall(request).execute();
  1. Authenticator proxyAuthenticator:代理认证,
  2. Authenticator authenticator:网络认证
  3. dns:dns提供自定义dns解析,默认为系统的
  4. boolean followSslRedirects:ssl重定向
  5. boolean followRedirects:重定向
  6. boolean retryOnConnectionFailure失败重试
  7. 时间设置
  final int callTimeout;
  final int connectTimeout;
  final int readTimeout;
  final int writeTimeout;
  1. ==connectionPool==
  • 复用http或http/2的连接; 减少网络延迟
  • 使用线程池进行连接的定时统计和清理
new ThreadPoolExecutor(0 /* corePoolSize */,
      Integer.MAX_VALUE /* maximumPoolSize */, 60L /* keepAliveTime */, TimeUnit.SECONDS,
      new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp ConnectionPool", true));
  • idleConnectionCount():空闲连接
  • RealConnection
  • put();如果清理连接没有运行,启动线程检查连接;并添加连接到ArrayDeque实现的队列
void put(RealConnection connection) {
    assert (Thread.holdsLock(this));
    if (!cleanupRunning) {
      cleanupRunning = true;
      executor.execute(cleanupRunnable);
    }
    connections.add(connection);
  }
  • cleanupRunnable
  1. cleanup(System.nanoTime()),如来连接在规定时间没有复用,结束
  2. 同时统计空闲的和使用的连接
long idleDurationNs = now - connection.idleAtNanos;(默认存活时间为5)

if (longestIdleDurationNs >= this.keepAliveDurationNs
          || idleConnectionCount > this.maxIdleConnections) {
        // We've found a connection to evict. Remove it from the list, then close it below (outside
        // of the synchronized block).
        connections.remove(longestIdleConnection);
      } else if (idleConnectionCount > 0) {
        // A connection will be ready to evict soon.
        return keepAliveDurationNs - longestIdleDurationNs;
      } else if (inUseConnectionCount > 0) {
        // All connections are in use. It'll be at least the keep alive duration 'til we run again.
        return keepAliveDurationNs;
      } else {
        // No connections, idle or in use.
        cleanupRunning = false;
        return -1;
      }

拦截器

拦截器调用机制

  • RealInterceptorChain
  • index
  • List interceptors
//该方法不需要重写
process(...){
    //增加index生成下一个拦截器的拦截连
    RealInterceptorChain next = new RealInterceptorChain(interceptors, ... index + 1, ... writeTimeout);
    
    //处理自身的拦截条件,并传递下一个连接
     Interceptor interceptor = interceptors.get(index);
    Response response = interceptor.intercept(next);
}

intercept(chain) {
    //处理自身的拦截条件
    ...
    //往下传递
   Response networkResponse = chain.proceed(requestBuilder.build());
   
   
   //返回结果
   return responseBuilder.build();
}

G09f3Q.png

系统默认的拦截器

  1. RetryAndFollowUpInterceptor
  • 处理失败和重定向下的情况
  • MAX_FOLLOW_UPS:最大重定向尝试次数
  1. BridgeInterceptor:构建http请求头header
  2. CacheInterceptor:
  • 从缓存里取
  • 请求成功存
  1. ConnectInterceptor
  • 连接目标服务,
HttpCodec httpCodec = streamAllocation.newStream(client, chain, doExtensiveHealthChecks);
 RealConnection connection = streamAllocation.connection();
return realChain.proceed(request, streamAllocation, httpCodec, connection);
  1. CallServerInterceptor
  • 向服务器进行网络请求