ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

Android 深入Http(4)从OkHttp源码来看Http,2021年你与字节跳动只差这份笔记

2022-01-10 12:59:19  阅读:197  来源: 互联网

标签:client Http chain interceptors Response 源码 2021 Interceptor final


Response response = getResponseWithInterceptorChain()

这行代码就突然Response了,这说明getResponseWithInterceptorChain()把Http的请求响应给走完了。也就是说它是最最最最关键的方法了。

已经了解完大框架,小结一下


学到这里我们看了好几个类,它们大概做的就是为Http铺好一条路,让http请求更好走,比如给它安排了线程,给Request包装等等,我们看一下关键的步骤:

  1. 将请求Requeset通过newCall方法包装成一个RealCall

  2. 执行RealCall()enqueue()方法,并且将Callback回调作为参数代入

  3. Dispatcher给该Request分配线程,放在后台,执行Dispatch自己的 execute()方法

  4. 这个execute()方法内部执行了 getResponseWithInterceptorChain(),该方法内部走完了http的传输细节,返回Response

  5. Response响应外面CallBack的 onResponse()onFailure()

注:其实这里就可以看出OkHttp无论是enqueue()还是execute(),都会走getResponseWithInterceptorChain(),因为execute()它不用切线程,所以它是直接执行该方法,而enqueue还要考虑当前请求是否太多,否则会造成阻塞,所以要用Dispatch来管理一下,再使用这个方法。

然后走完这个方法,就会去回调之前Callback的onResponse和onFailure方法了。

上面就是OkHttp的大框架了,其实很简单,所以外面用起来也很简单,好懂。

为了更深入的了解OkHttp,我们除了了解这些,还要去了解它里面的一些配置,和网络实现的细节。

也就是OkHttpClient 它是做什么的,和 getResponseWithInterceptorChain()这个方法

OkHttpClient


我们先来看看OkHttpClient里面的全部配置。每个都注释一下,并讲述比较重要的对象:

//线程管理器,这个之前已经了解了

final Dispatcher dispatcher;

//代理类,帮我们配置网络信息

final @Nullable Proxy proxy;

//Protocol类里面列出了支持的Http版本,http1.0、1.1、2.0 SPDY3.1(http2的前身)

final List protocols;

//里面是Cipher Suite(如果是Https,那么这个Cipher suite就是TLS版本、对称加密、非对称加密、Hash算法…,让对方选,所以这里是一个列表)

//它有好几套Cipher Suite方案任君选择

final List connectionSpecs;

//这两个比较重要,等下会具体研究,它们大概就是对连接过程中的每一个阶段做处理

final List interceptors;

final List networkInterceptors;

//就是监听整个网络请求+返回过程

final EventListener.Factory eventListenerFactory;

//用处不大,不用了解了

final ProxySelector proxySelector;

//Jar是罐子的意思,CookieJar是存放Cookie的容器

final CookieJar cookieJar;

//Http的Cache

final @Nullable Cache cache;

final @Nullable InternalCache internalCache;

//Socket是Tcp的端口,这个就是Tcp端口的工厂

final SocketFactory socketFactory;

//Https下Tcp的端口

final @Nullable SSLSocketFactory sslSocketFactory;

//证书链,方便验证(https讲过)

final @Nullable CertificateChainCleaner certificateChainCleaner;

//Https验证的 主机名验证器, 验证对方的Host是不是想要访问的Host

final HostnameVerifier hostnameVerifier;

//直译叫证书固定器,用来做自签名,用来验证证书公钥,如果host的证书和这个对象传入(本地存的)的公钥一致,则证明对方是自己想要访问的一方。

final CertificatePinner certificatePinner;

//用来写 Authorization Bearer<…> 当权限不足的时候会报错 401

final Authenticator proxyAuthenticator;

final Authenticator authenticator;

//线程连接池,可以有那么多的线程可以用来进行网络请求

final ConnectionPool connectionPool;

//DNS实现类

final Dns dns;

//重定向跳转, 默认为true,即跳转

final boolean followRedirects;

//https跳到http重定向,默认为true

final boolean followSslRedirects;

//当连接建立失败后,是否重试,默认为true

final boolean retryOnConnectionFailure;

//Tcp连接、读、写 超过该时间就跑错

final int connectTimeout;

final int readTimeout;

final int writeTimeout;

//长连接,发送ping(相当于一个心跳)的时间间隔

final int pingInterval;

看完上面的配置还有一些注释,会很明白HTTP在OkHttp里面的配置,比较全而且清晰。

OkHttpClient这个大总管它有关于Http、Https基本都有的配置信息,基本都是Header和Header有关的一些东西。

getResponseWithInterceptorChain()


OkHttp最核心的方法,相当于内部的入口。所以很有必要去了解。

我们先点进这个方法:

Response getResponseWithInterceptorChain() throws IOException {

// Build a full stack of interceptors.

//第一部分

List 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);

//第三部分

return chain.proceed(originalRequest);

}

上面比较“麻雀虽小五脏俱全”的感觉,代码没那么多,但每一行都是核心。

它大概有三个部分:

  1. 装一些Interceptor到List中

  2. 构建一个 Interceptor Chain

  3. 使用chain的 proceed(originalRequest)得到了网络响应的Response

我们用图分别来说下他们的概念:

在这里插入图片描述

首先这个方法会创建一个含有泛型为Interceptor的List,并往这个List里面add几个系统自带的Interceptor。如上图所示。

chain的构造方法中带了这个List,也就是说,这个chain它其实是给这个List里的所有interceptor用一条链,按顺序给链了起来,如下图:

在这里插入图片描述

↑而且实际上,这条链并不是单向的,它走到走后的Interceptor后,会往回走。

原因很简单,chain的方向就是我们Request走的方向,我们把Request带过去(发送请求),最后会把Respnse带回来,回来的时候,也要这些Interceptor来处理结果。这就是chain。

为什么要用Chain和Interceptor,为什么不直接发到另一端去


那肯定是细节化啊。

万一你突然Request少了一个重要东西,我有必要在检查少了东西的这个环节进行上报,如果直接传过去,可能会产生不必要的开销。

chain的目的在于每个Interceptor都能够自定义的去处理这些事情,所以chain和Interceptor是多么滴重要。

chain.proceed(Requset)


process(request)是做什么的呢?process是前进的意思。

概述:将Request交个下一个Interceptor处理

将代码和图来讲一下:

它有三个情况,一个是将requeset,传过去,一个是等,一个是request/response回来:

(1)执行proceed()方法

在这里插入图片描述

Interceptor1的时候执行了proceed(request),将request传给Interceptor2

(2)等Chain回来

在这里插入图片描述

(3)Chain回来了,得到Interceptor2给Interceptor的东西了,就可以去处理这个东西了

![在这里插入图片描述](https://www.icode9.com/i/ll/?i=2019070
5172033310.png)

每个节点都会这样走,并且他们有做实际的对Request的操作(比如传Request之前,我们要作什么,拿回来Response后,我们要做什么)。所以按照顺序,我们来看下getRespnseWithInterceptorChain()里面的Interceptor

Interceptor概述


List 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));

首先 interceptors.addAll(client.interceptors());interceptors.addAll(client.networkInterceptors());是用来加我们自定义的Interceptor(如果没有自定义,这个就是空的)的,别的Interceptor都是OkHttp自带的,我们后面再讲自定义的,先来看下OkHttp自带的Interceptor。

retryAndFollowUpInterceptor


retry就是重试,FollowUp就是重定向。我们来看下它的源码:

而每个Interceptor最重要的方法就是它们的intercept(Chain)方法,这个方法就是和上面一样做这些事情:

①处理别人给我的request1,处理完后变成request2

②执行 chain.process(request2)

③等待别的Interceptor处理完,给我传Response

④处理这个Response

就是会有一个模板代码:

//Interceptor的 intercept的模板代码

public Response intercept(Chain chain) {

//获取requeset

Request request = chain.requeset();

//前置方法,处理Requeset

response = chain.process(requeset);

//后置方法,处理Response

}

OK,看完这些,我们来看关于处理重定向的Interceptor的源码:

@Override public Response intercept(Chain chain) throws IOException {

Request request = chain.request();

//StreamAllocation: Streams是OkHttp中一个很重要的概念,它的含义是http连接时产生Request/Response对

streamAllocation = new StreamAllocation(

client.connectionPool(), createAddress(request.url()), callStackTrace);

while (true) {

try {

response = ((RealInterceptorChain) chain).proceed(request, streamAllocation, null, null);

releaseConnection = false;

} catch (RouteException e) {

// The attempt to connect via a route failed. The request will not have been sent.

if (!recover(e.getLastConnectException(), false, request)) {

throw e.getLastConnectException();

}

if (followUp == null) {

if (!forWebSocket) {

streamAllocation.release();

}

return response;

}

process()方法其实是一个递归,一个Interceptor走了process(),那么这个process()方法就是给它的下一个Interceptor走process()…直到最后走完返回来,它得到的Response其实就是它后面全部走完后得到,返回的Response。

当我们重定向的Interceptor出现了需要重定向的时候,就会走代码中catch{}cover()方法其实就是重定向的方法,它根据OkHttp的配置(比如之前看过的 retryOnConnectionFailure的字段,如果是false,就不会进行重定向了…)然后根据这些配置去改变Request,更改地址信息,最终得到结果。

这个方法是while(true)包裹的,所以,它如果出现了重定向,一定会循环走。

重定向的Interceptor嘛…主要都是把精力集中在后置代码上。比较清楚的知道它在干什么。

我们来看下一个Interceptor把。

BridgeInterceptor(client.cookieJar())


桥接Interceptor。

往下看:

在这里插入图片描述

在这里插入图片描述

直到proceed()方法前,我们一目了然桥接Interceptor的前置方法,就是在给Http报文添加 请求头 Headers

它会添加ContentType、Content-Length、User-Agent…

需要注意的是,上面Accpet-Encodeing中,如果我们没有自定义接收编码格式,OkHttp会默认是gzip

你都给我默认gzip,万一我自己解不了gzip怎么办,没问题,OkHttp会自己解析gzip(就在这边的后置代码中)~

而后置代码都是对数据Response的解析一遍。,这就是BridgeInterceptor()

CacheInterceptor(client.internalCache())


不就是Cache吗。

Cache方法里面会先创建一个CacheStrategy,然后根据这个实例去查看拿来的Request它有没有Response(就是在本地有没有Cache)

在这里插入图片描述

↓如果我们本地有cache了,那我们就不用再去做网络请求了,这个时候会直接return 伪造一个Response给上个在等proceed()方法的Interceptor。

在这里插入图片描述

总结:

  • 如果对于这个Request有cache,并且这个cache没有过期,则CacheInterceptor不会走proceed()方法,会直接返回cache的Response

  • 如果没有cache,才会走proceed()方法,走之后的网络请求。

从这里也可以看出,Interceptor有它分出来的好处。

ConnectInterceptor


这个地方是真正的和TCP、TLS做交互的地方,就是做连接的地方,它最主要的代码是下面:

在这里插入图片描述

通过newStream()能得到一个HttpCodec对象,它用于编码与解码(Http1.1用的是纯文本和http2.0用的是纯二进制)

connection()里面会去建立Tcp连接(里面会走 connectSocket()connectTLS()方法)。

之前的OkHttpClient配置全都在RealConnection()用到了。

该Interceptor几乎是最后一个Interceptor,因为它做了连接,所以它没有后置方法,直接返回response。

CallServerInterceptor


标签:client,Http,chain,interceptors,Response,源码,2021,Interceptor,final
来源: https://blog.csdn.net/m0_66144836/article/details/122408076

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有