OkHttp讲义
OkHttp 使⽤⽅法简介
创建⼀个
OkHttp
的实例1
OkHttpClient client = new OkHttpClient.Builder().build();
创建
Request
1
2
3Request request = new Request.Builder()
.url("http://hencoder.com")
.build();创建
Call
并发起⽹络请求1
2
3
4
5
6
7
8
9
10client.newCall(request).enqueue(new Callback() {
public void onFailure(Call call, IOException e) {
}
public void onResponse(Call call, Response response) throws IOException{
Log.d("okhttp response", response.body().string());
}
});enqueue: 异步的
excute: 同步的
OkHttp 源码总结
OkHttpClient
相当于配置中⼼,所有的请求都会共享这些配置(例如出错是否重试、共享的连接池)。OkHttpClient
中的配置主要有:Dispatcher dispatcher
:调度器,⽤于调度后台发起的⽹络请求,有后台总请求数和单主机总请求数的控制。List<Protocol> protocols
:⽀持的应⽤层协议,即HTTP/1.1
、HTTP/2
等。List<ConnectionSpec> connectionSpecs
:应⽤层⽀持的Socket
设置,即使⽤明⽂传输(⽤于HTTP
)还是某个版本的TLS
(⽤于HTTPS
)。其中的clearText
(“明文”没有用加密)等同于http
List<Interceptor> interceptors
:⼤多数时候使⽤的Interceptor
都应该配置到这⾥。List<Interceptor> networkInterceptors
:直接和⽹络请求交互的Interceptor
配置到这⾥,例如如果你想查看返回的301
报⽂或者未解压的Response Body
,需要在这⾥看。CookieJar cookieJar
(饼干存储罐):管理Cookie
的控制器。OkHttp
提供了Cookie
存取的判断⽀持(即什么时候需要存Cookie
,什么时候需要读取Cookie
,但没有给出具体的存取实现。
如果需要存取Cookie
,你得⾃⼰写实现,例如⽤Map
存在内存⾥,或者⽤别的⽅式存在本地存储或者数据库。Cache cache
:Cache
存储的配置。默认是没有,如果需要⽤,得⾃⼰配置出Cache
存储的⽂件位置以及存储空间上限。HostnameVerifier hostnameVerifier
:⽤于验证HTTPS
握⼿过程中下载到的证书所属者是否和⾃⼰要访问的主机名⼀致。- sokect是tcp的端口(http是没有端口一说)
CertificatePinner certificatePinner
:⽤于设置HTTPS
握⼿过程中针对某个Host
的Certifificate Public Key Pinner
,即把⽹站证书链中的每⼀个证书公钥直接拿来提前配置进OkHttpClient
⾥去,以跳过本地根证书,直接从代码⾥进⾏认证。这种⽤法⽐较少⻅,⼀般⽤于防⽌⽹站证书被⼈仿制。Authenticator authenticator
:⽤于⾃动重新认证。配置之后,在请求收到401
(权限不足)状态码的响应是,会直接调⽤authenticator
,⼿动加⼊Authorization header
之后⾃动重新发起请求。boolean followRedirects
:遇到重定向的要求是,是否⾃动follow
。boolean followSslRedirects
在重定向时,如果原先请求的是http
⽽重定向的⽬标是https
,或者原先请求的是https
⽽重定向的⽬标是http
,是否依然⾃动follow
。(记得,不是「是否⾃动follow HTTPS URL
重定向的意思,⽽是是否⾃动follow
在HTTP
和HTTPS
之间切换的重定向)boolean retryOnConnectionFailure
:在请求失败的时候是否⾃动重试。注意,⼤多数的请求失败并不属于OkHttp
所定义的「需要重试」,这种重试只适⽤于「同⼀个域名的多个IP
切换重试」「Socket
失效重试」等情况。int connectTimeout
:建⽴连接(TCP
或TLS
)的超时时间。int readTimeout
:发起请求到读到响应数据的超时时间。int writeTimeout
:发起请求并被⽬标服务器接受的超时时间。(为什么?因为有时候对⽅服务器可能由于某种原因⽽不读取你的Request
)
newCall(Request)
⽅法会返回⼀个RealCall
对象,它是Call
接⼝的实现。当调⽤RealCall.execute()
的时候,RealCall.getResponseWithInterceptorChain()
会被调⽤,它会发起⽹络请求并拿到返回的响应,装进⼀个Response
对象并作为返回值返回;RealCall.enqueue()
被调⽤的时候⼤同⼩异,区别在于enqueue()
会使⽤Dispatcher
的线程池来把请求放在后台线程进⾏,但实质上使⽤的同样也是getResponseWithInterceptorChain()
⽅法。getResponseWithInterceptorChain()
⽅法做的事:把所有配置好的Interceptor
放在⼀个List
⾥,然后作为参数,创建⼀个RealInterceptorChain
对象,并调⽤chain.proceed(request)
来发起请求和获取响应。在
RealInterceptorChain
中,多个Interceptor
会依次调⽤⾃⼰的intercept()
⽅法。这个⽅法会做三件事:- 对请求进⾏预处理
- 预处理之后,重新调⽤
RealIntercepterChain.proceed()
把请求交给下⼀个Interceptor
- 在下⼀个
Interceptor
处理完成并返回之后,拿到 Response 进⾏后续处理
当然了,最后⼀个 Interceptor 的任务只有⼀个:做真正的⽹络请求并拿到响应
从上到下,每级
Interceptor
做的事:- ⾸先是开发者使⽤
addInterceptor(Interceptor)
所设置的,它们会按照开发者的要求,在所有其他Interceptor
处理之前,进⾏最早的预处理⼯作,以及在收到Response
之后,做最后的善后⼯作。如果你有统⼀的header
要添加,可以在这⾥设置; - 然后是
RetryAndFollowUpInterceptor
:它负责在请求失败时的重试,以及重定向的⾃动后续请求。它的存在,可以让重试和重定向对于开发者是⽆感知的; BridgeInterceptor
:它负责⼀些不影响开发者开发,但影响HTTP
交互的⼀些额外预处理。例如,Content-Length
的计算和添加、gzip
的⽀持(Accept-Encoding: gzip
)、gzip
压缩数据的解包,都是发⽣在这⾥;CacheInterceptor
:它负责Cache
的处理。把它放在后⾯的⽹络交互相关Interceptor
的前⾯的好处是,如果本地有了可⽤的Cache
,⼀个请求可以在没有发⽣实质⽹络交互的情况下就返回缓存结果,⽽完全不需要开发者做出任何的额外⼯作,让Cache
更加⽆感知;ConnectInterceptor
:它负责建⽴连接。在这⾥,OkHttp
会创建出⽹络请求所需要的TCP
连接(如果是HTTP
),或者是建⽴在TCP
连接之上的TLS
连接(如果是HTTPS
),并且会创建出对应的HttpCodec
对象(⽤于编码解码HTTP
请求);- 然后是开发者使⽤
addNetworkInterceptor(Interceptor)
所设置的,它们的⾏为逻辑和使⽤addInterceptor(Interceptor)
创建的⼀样,但由于位置不同,所以这⾥创建的Interceptor
会看到每个请求和响应的数据(包括重定向以及重试的⼀些中间请求和响应),并且看到的是完整原始数据,⽽不是没有加Content-Length
的请求数据,或者Body
还没有被gzip
解压的响应数据。多数情况,这个⽅法不需要被使⽤; CallServerInterceptor
:它负责实质的请求与响应的I/O
操作,即往Socket
⾥写⼊请求数据,和从Socket
⾥读取响应数据。
- ⾸先是开发者使⽤
作业
阅读 OkHttp
源码,理解 OkHttp
原理,并尝试在不借助讲义的情况下讲出 OkHttpClient
中每个重要的成员变量的⽤途,以及每个 Interceptor
的实际作⽤。(不检查)
WebSocket
是HTTP
的扩展,一般用于金融交易(股票等)
HTTP
是C/S
HTTP
是无连接的,连接说的是TCP
和SSL
(TLS
)连接