说到网络请求框架,OkHttp应该是当下较为流行的了,原因就在于它简单易用,且高效。同样,也是Square公司的作品。
1. 引入
库地址
添加依赖时,在app的build.gradle加一个库即可
1 | implementation("com.squareup.okhttp3:okhttp:4.9.3") |
2. 使用
使用OkHttp发送网络请求,一般分为5个步骤
- 生成OkHttpClient
Client可以配置一些和连接相关的参数,比如连接timeout、读timeout、写timeout、连接池的配置、添加拦截器,等等 - 生成Request
Request可以设定和请求相关的参数,如请求的URL、请求方式、请求头、请求的body - 生成Call
一个Call,即为一个网络请求,这一步需要上面的Client和Request - 发送Call
将请求发出,这里有两种方式,一种是同步发送,会阻塞线程,等待数据返回;另一种是异步发送,在回调里处理返回的数据 - 等待Call返回Response
Response即为服务器返回的数据,包含Header,和Body其中,Client也可以定制化,和Request类似,也是使用构建者模式1
2
3
4
5
6
7OkHttpClient client = new OkHttpClient();
Request requst = new Request.Builder().url("").get().build();
Call call = client.newCall(request);
Response response = call.execute(); // 同步
call.enqueue(callback); // 异步
String message = response.body().string();1
2
3
4
5
6OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(60, TimeUnit.SECONDS)
.readTimeout(60, TimeUnit.SECONDS)
.writeTime(60, TimeUnit.SECONDS)
.connectionPool(new ConnectionPool(30, 30, TimeUnit.MINUTES))
.build();
3. 责任链
责任链是OkHttp中最巧妙的设计了。链上的每个元素,抽象成了一个拦截器Interceptor,每个拦截器都可以处理Request和Response。这种设计的好处就是,将处理者和请求者解耦,缺点就是,每次发起请求需要对链上的拦截者遍历,当拦截者过多时会影响性能。
什么意思呢,简单说就是,每次发起网络请求,Request会经过责任链上的每一个拦截器,最终到达服务器,同样,服务器返回的Response也会经过链上的每一个拦截器,最终回到请求者。比如,你想给每个请求都加上一个包含鉴权的Header,那么只需要向责任链中插入一个拦截器,这样就可以触碰到所有的Request和Response,不需要操作Response,而只需要向Resquest的Header中增加一对Key-Value即可,这种模式下,不需要关心谁发起的请求,也不需要关心谁将会处理请求,只需要插入一个拦截器Interceptor即可。
这里面有两个角色,一个是链,一个是拦截器。
先说拦截器。拦截器本身是拿不到任何东西的,它只有插入到责任链上之后,才能操作Request和Response,所以,它的Request是链提供给它的,同时,它还要返回一个Response,才能保证责任链能完整的流通,不然其中某个拦截器,在拿到Request后,不返回Response,那么,请求到这里就断掉了。一个链上可以有多个拦截器,Interceptor是个接口,其中只有一个interceptor方法,自定义的拦截器需要实现这个方法,Chain提供了多个方法,来提供和请求相关的参数,比如连接timeout、读写timeout,当然,还包括Request
1 | public interface Interceptor { |
看完拦截器,再来看看另外一个角色,链。Chain也是一个接口,它只有一个实现类,RealInterceptorChain,看看request方法是如何获取到Request,proceed方法又是如何获取到Response的。
1 | public Request request() { |
request方法很简单,就是直接返回的成员变量request,而这个变量是在构造方法里面传入的,就没什么可多说的了。那就再看看proceed方法,
1 | public Response proceed(Request request, Transmitter transmitter, Exchange exchange) |
里面做了一些检查和判断,关键的就是中间的创建next变量。next的类型还是RealInterceptorChain,构造方法中第一个参数就是所有的拦截器,还有个index参数,表明这个next用的是第几个拦截器,换句话说就是,每个拦截器都对应一个RealInterceptorChain类型的变量。初始化next,又获取到了拦截器,通过interceptor.intercept(next)来获取response,来返回给上面的chain.proceed(request)。
可能有点乱,来捋一捋。一个拦截器想要获取Request很简单,Chain的构造方法里便有。一拦截器想要获取Response时,Chain就会获取到链中的下一个拦截器,通过调用它的intercept方法来获取Response,进入到下一个拦截器的intercept方法中时,它的Response又要通过Chain获取下下一个拦截器,跟它要Response。形象点来说就是,A想要操作Response,它就会带着Request和B要Response,B又会带着Request和C要Response,C又会和D要,就这么一直在链上传递下去。那么大家都这么踢皮球一样踢来踢去,真正的Response从何而来呢?从要有个兜底的吧?没错,真有一个兜底的,它就是链上的最后一个拦截器,CallServerInterceptor。
所以,还要再看看发送请求前,都给链上添加了那些拦截器。
上面说过,发送网路请求时,最终会生成一个Call,然后将其发出,而Call是一个接口,它只有一个实现类,叫做RealCall,不管是调用的Call的同步方法execute还是异步方法enqueue,最终都会来到RealCall里的getResponseWithInterceptorChain方法,完整内容如下,
1 | Response getResponseWithInterceptorChain() throws IOException { |
可以看到,发送请求前,除了添加我们给Client添加的拦截器,OkHttp还添加了一些自己的拦截器,用来对Request和Response做一些处理。最后一个拦截器,便是CallServerInterceptor
1 | // This is the last interceptor in the chain. It makes a network call to the server. |
它的类说明里,写的是链中的最后一个拦截器。所以她没办法再踢皮球,和别人要Response。它的intercept方法里,将上游传来的request发送出去,然后等服务器返回,将数据封装成Response,再度返回给链上游。
总结来看就是,每个拦截器中,想要操作Response,需要将自己处理过的Request传给链下游,下游接着往下传递,直到到达链末端的CallServerInterceptor,它向服务器发送请求,接收服务器的响应,然后再将Response回传给链上游,直到到达请求发送者,这个请求算作结束。