okHttp的网络实现(源码原理)

        上一节,聊了HttpConnection对于网络的实现,是默认外包的,外包方大多取决于定制的平台。带有不确定性,OkHttp最初作为三方网络请求框架,可以做到一致性。以及OkHttp在框架封装,接口提供等方面所提供的library的功能性,易用性,稳定性和高效性,是市面上android_java中比较好和主流的一款。

     这里直接从RealCall下手了。

    这里同样对于框架的封装和设计,不多聊。直接说其最核心的请求部分的做法。无论是否是异步,最初构建请求逻辑的都是一个方法:

  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));
//RealInterceptorChain这个类是OkHttp所有配置和功能作为的核心新,把所有东西凝结在一起。
//根据这个类的构造看,当初设计者是怀有怎样巨大的梦想。
    Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,originalRequest, this, eventListener, client.connectTimeoutMillis(),
        client.readTimeoutMillis(), client.writeTimeoutMillis());

    return chain.proceed(originalRequest);
  }
可以看到,ok把对网络所有请求,通过一系列实现Interceptor接口的拦截器来配置,这些拦截器具体怎么工作的,下面聊,必须说明, 拦截器的顺序非常重要 ,最先add的最先执行,越是在后面执行,才越是一个请求的核心。整个拦截器的集合采用链式调用。
看看有哪些拦截器:
RetryAndFollowUpInterceptor:负责失败重试和重定向。
        proceed内部包含一个 
streamAllocation = new StreamAllocation(client.connectionPool(), createAddress(request.url()),call, eventListener, callStackTrace); 实例化动作
        和while true包裹的包含 response = realChain.proceed(request, streamAllocation, null, null);逻辑。followUpRequest()会根据每次响应responseCode的结果,决定下一个请求使用的数据,比如重定向,授权等,当followUpRequest()返回null的时候,表示请求的最终结束。
BridgeInterceptor:负责把用户构造的请求转换为发送到服务器的请求、把服务器返回的响应转换为用户友好的响应。
        这个类没什么,就是在请求之前和请求之后,把对结果和内容的一些信息,重新设置到head头等操作。
CacheInterceptor:这个缓存就是OkHttpClient设置的cache参数对应的实例,他所做的事情,就是在请求之前,读取缓存,如果没有缓存模块或者缓存没有达到要求,也就是new CacheStrategy.Factory(now, chain.request(), cacheCandidate).get()获得的信息为空。
         在请求完成得到相应后,根据是否有缓存模块把数据刷新到缓存内。
ConnectInterceptor:负责和服务器建立连接。
        这里比较简单,就是使用StreamAllocation,进行网络请求,开启connection.
CallServerInterceptor:负责向服务器发送请求数据、从服务器读取响应数据。
        这个类,才是最后一个拦截器,不再调用proceed,而是把请求处理,返回响应。

**************************************************************************************

        到这里,我们可以知道,核心请求的实现,是在 StreamAllocation 和 CallServerInterceptor这两个类中做转接的。
这里有必要,包ConnectInterceptor的实现贴出来,给我们指引方向:

public Response intercept(Chain chain) throws IOException {
    RealInterceptorChain realChain = (RealInterceptorChain) chain;
    Request request = realChain.request();
    StreamAllocation streamAllocation = realChain.streamAllocation();
    // We need the network to satisfy this request. Possibly for validating a conditional GET.
    boolean doExtensiveHealthChecks = !request.method().equals("GET");
    HttpCodec httpCodec = streamAllocation.newStream(client, chain, doExtensiveHealthChecks);
//newStream方法执行了两个关键的东西。findHealthyConnection(while(true)判断连接是否可用isHealthy)->findConnection(从连接池中取出连接(RealConnection),没有则重新new RealConnection()并开启连接)..然后调用这个连接RealConnection的newCodec方法返回。new Http2Codec new Http1Codec两种形式。
    RealConnection connection = streamAllocation.connection();
    return realChain.proceed(request, streamAllocation, httpCodec, connection);
  }
        也就是说在proceed  CallServerInterceptor这个拦截器之前,streamAlocation已经开启 connection方法,并且把返回的RealConnection作为proceed的参数。同时还有newStream处理得到的HttpCodec。
        最难理解的还是在  CallServerInterceptor 和 RealConnection 。
        在CallServerInterceptor中,对 httpCodec 直接写入head (writeRequestHeaders)并且flushRequest,然后直接去
readResponseHead ,如果是空则需要去使用httpCodec去构建createResponseBody。这里会使用Okio去读取流。

//在 RealConnection 中。  
public HttpCodec newCodec(OkHttpClient client, Interceptor.Chain chain,
      StreamAllocation streamAllocation) throws SocketException {
    if (http2Connection != null) {
      return new Http2Codec(client, chain, streamAllocation, http2Connection);
    } else {
      socket.setSoTimeout(chain.readTimeoutMillis());
      source.timeout().timeout(chain.readTimeoutMillis(), MILLISECONDS);
      sink.timeout().timeout(chain.writeTimeoutMillis(), MILLISECONDS);
      return new Http1Codec(client, streamAllocation, source, sink);
    }
  }
RealConnection -> connectSocket() -> Platform.get().connectSocket(,,);//sokect连接方法的位置。
//Okio自己实现的读写包装,加入了读写延迟      
source = Okio.buffer(Okio.source(rawSocket));
sink = Okio.buffer(Okio.sink(rawSocket));

今天按照这个粒度,分析到这里。整个框架是有一定复杂度的,设计上非常具有扩展性,带有包装层,而开发人员同时可自定义一定的深度。。。。

网络上关于OkHttp的优点,来源未知:
OkHttp是一个现代,快速,高效的Http client,支持HTTP/2以及SPDY,一种开放的网络传输协议,由Google开发),它为你做了很多的事情。
OKHttp是Android版Http客户端。非常高效,支持SPDY、连接池、GZIP和HTTP缓存。
支持SPDY,可以合并多个到同一个主机的请求
OkHttp实现的诸多技术如:连接池,gziping,缓存等就知道网络相关的操作是多么复杂了。
OkHttp扮演着传输层的角色。
OkHttp使用Okio来大大简化数据的访问与存储,Okio是一个增强 java.io 和 java.nio的库。
OkHttp 处理了很多网络疑难杂症:会从很多常用的连接问题中自动恢复。如果您的服务器配置了多个IP地址,当第一个IP连接失败的时候,OkHttp会自动尝试下一个IP。
OkHttp还处理了代理服务器问题和SSL握手失败问题。
OkHttp是一个Java的HTTP+SPDY客户端开发包,同时也支持Android。需要Android 2.3以上
OKHttp是Android版Http客户端。非常高效,支持SPDY、连接池、GZIP和 HTTP 缓存。
默认情况下,OKHttp会自动处理常见的网络问题,像二次连接、SSL的握手问题。
如果你的应用程序中集成了OKHttp,Retrofit默认会使用OKHttp处理其他网络层请求。
从Android4.4开始HttpURLConnection的底层实现采用的是okHttp 
    缓存响应避免重复的网络请求
目前,该封装库志支持:
•     一般的get请求
•     一般的post请求
•     基于Http的文件上传
•     文件下载
•     上传下载的进度回调
•     加载图片
•     支持请求回调,直接返回对象、对象集合
•     支持session的保持
•     支持自签名网站https的访问,提供方法设置下证书就行
•     支持取消某个请求

发布了155 篇原创文章 · 获赞 125 · 访问量 34万+

猜你喜欢

转载自blog.csdn.net/u011216417/article/details/79044400