OKHttp
介绍
- OkHttp 是一套处理 HTTP 网络请求的依赖库,可以在 Java 和 Kotlin 中使用。对于 Android App 来说,OkHttp 现在几乎已经占据了所有的网络请求操作,它还提供了拦截器、连接池、缓存等功能,可以优化网络请求的性能和可靠性,我们了解其内部实现原理可以更好地进行功能扩展、封装以及优化。
依赖
implementation("com.squareup.okhttp3:okhttp:4.10.0")
implementation("com.squareup.okhttp3:logging-interceptor:4.10.0")
Get请求
- 同步请求
public void getSync() {
new Thread(() -> {
try {
//创建OkHttpClient对象
OkHttpClient client = new OkHttpClient();
//创建Request
Request request = new Request.Builder()
.url("https://www.toutiao.com/")//访问连接
.get()
.build();
//创建Call对象
Call call = client.newCall(request);
//通过execute()方法获得请求响应的Response对象
Response response = call.execute();
if (response.isSuccessful()) {
//处理网络请求的响应,处理UI需要在UI线程中处理
}
} catch (IOException e) {
e.printStackTrace();
}
}).start();
}
这是一个使用OkHttp进行同步网络请求的示例。首先创建一个OkHttpClient对象,然后通过Request.Builder构建一个请求对象,指定访问连接和请求方法等参数。接着通过client.newCall(request)创建一个Call对象,并调用execute()方法发送请求并获得响应的Response对象。
- 异步请求
private void Asynchronous() {
//创建一个OkHttpClient对象
OkHttpClient okHttpClient = new OkHttpClient.Builder()
//使用默认请求时间,超出就是失败
//建造
.build();
// 创建一个Request对象
Request request = new Request.Builder()
//设置正确的url
.url("https://www.toutiao.com/")
.build();
//建立一个Call对象
Call call = okHttpClient.newCall(request);
//Call对象发起网络请求
call.enqueue(new Callback() {
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) {
Toast.makeText(MainActivity.this, "请求失败", Toast.LENGTH_SHORT).show();
}
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
if (response.code() == 200) {
String data = response.body().string();
Log.d("Project", "请求成功:" + data);
} else {
Log.d("Project", "请求失败了" + response.code());
Log.d("Project", "请求失败了" + response.body().string());
}
}
});
}
这是一个使用OkHttp进行异步请求的示例。首先创建一个OkHttpClient对象,并通过Builder设置一些参数,比如默认请求时间等。然后创建一个Request对象,指定访问的URL。接着通过okHttpClient.newCall(request)创建一个Call对象。调用call.enqueue()方法发起异步网络请求,并传入一个Callback对象作为回调函数。在回调函数中,onFailure()方法会在请求失败时被调用,可以在这里处理请求失败的情况。onResponse()方法会在请求成功时被调用,可以在这里处理请求成功的情况。
Post请求
Post请求与Get请求不同的地方在于Request.Builder的post()方法,post()方法需要一个RequestBody的对象作为参数
private void postRequest() {
OkHttpClient client = new OkHttpClient();
// 创建RequestBody对象,用于封装请求参数
RequestBody requestBody = new FormBody.Builder()
.add("username", "test")
.add("password", "123456")
.build();
// 创建Request对象,指定POST请求方式和请求体
Request request = new Request.Builder()
.url("https://www.wanandroid.com/user/login")
.post(requestBody)
.build();
// 发起异步POST请求
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) {
// 请求失败处理逻辑
}
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
if (response.isSuccessful()) {
// 请求成功处理逻辑
String responseData = response.body().string();
} else {
// 请求失败处理逻辑
}
}
});
}
我们来看这个例,首先创建一个OkHttpClient对象。然后通过FormBody.Builder创建一个RequestBody对象,用于封装POST请求的参数。接着创建一个Request对象,指定访问的URL、POST请求方式和请求体。最后通过client.newCall(request).enqueue()方法发起异步POST请求,并传入一个Callback对象作为回调函数。在回调函数中,onFailure()方法会在请求失败时被调用,可以在这里处理请求失败的情况。onResponse()方法会在请求成功时被调用,可以在这里处理请求成功的情况。如果响应的状态码是200,则可以通过response.body().string()获取响应体的字符串形式,并进行相应的处理。如果状态码不是200,则可以通过response.code()获取状态码,进行错误处理。
RequestBody
- RequestBody是OkHttp库中的一个类,用于封装HTTP请求的请求体,可以用于POST、PUT等请求方式。RequestBody对象可以包含各种类型的数据,比如文本、文件等。下面这个就是post一个文件的方式,过addFormDataPart()方法添加要上传的文件。这里使用了application/octet-stream作为文件的MediaType。
// 创建请求体
RequestBody requestBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("file", file.getName(), RequestBody.create(MediaType.parse("application/octet-stream"), file))
.build();
OKHttp 拦截器
拦截器是OkHttp当中一个比较强大的机制,可以监视、重写和重试调用请求。其中还分为应用拦截器和网络拦截器。应用拦截器是最先执行的拦截器,也就是用户自己设置request属性后的原始请求,而网络拦截器位于ConnectInterceptor和CallServerInterceptor之间,此时网络链路已经准备好,只等待发送请求数据,
首先应用拦截器在RetryAndFollowUpInterceptor和CacheInterceptor之前,所以一旦发生错误重试或者网络重定向,网络拦截器可能执行多次,因为相当于进行了二次请求,但是应用拦截器永远只会触发一次。另外如果在CacheInterceptor中命中了缓存就不需要走网络请求了,因此会存在短路网络拦截器的情况。
然后除了CallServerInterceptor之外,每个拦截器都应该至少调用一次realChain.proceed方法。实际上在应用拦截器这层可以多次调用proceed方法(本地异常重试)或者不调用proceed方法(中断),但是网络拦截器这层连接已经准备好,可且仅可调用一次proceed方法。
最后从使用场景看,应用拦截器因为只会调用一次,通常用于统计客户端的网络请求发起情况;而网络拦截器一次调用代表了一定会发起一次网络通信,因此通常可用于统计网络链路上传输的数据。
我们再来了解一下应用拦截器的5种拦截器
1. RetryAndFollowUpInterceptor(重试和重定向拦截器):这个拦截器用于在请求失败时进行重试。它可以根据设定的条件,如最大重试次数、重试间隔等判断是否需要重新发起整个请求。它可以处理一些网络故障或临时错误,提高请求的可靠性
2. BridgeInterceptor(桥接拦截器):帮助我们把用户的请求翻译成计算机能够理解的语言,然后发送给网络进行处理。它处理请求和响应之间的桥梁工作,包括添加请求头、读取响应数据等,完成应用层和网络层的桥接。这个拦截器的作用就是完成应用层和网络层之间的桥接工作,确保它们能够顺利地进行沟通和协作。
3. CacheInterceptor(缓存拦截器):这个拦截器用于实现HTTP缓存机制。它可以根据请求的缓存策略,从缓存中获取响应或将响应保存到缓存中。
4. ConnectInterceptor(链接拦截器):这个拦截器用于与服务器完成TCP连接,内部维护一个连接池,处理连接的生命周期,包括连接的创建、复用和关闭等。
5. CallServerInterceptor(请求服务拦截器):这个拦截器负责执行实际的网络请求并获取响应数据。它将用户的请求发送到服务器,并接收服务器的响应数据,处理网络请求和响应的整个过程。
OKHttp 分发器
- OkHttp的分发器是负责调度和执行网络请求的组件,它维护着一个请求队列和线程池。当有多个异步请求时,分发器会将它们按照请求状态分为正在请求中和正在等待的列表,并根据配置的并发请求数量来控制同时进行的请求数量。请求完成后,分发器会从等待中的列表中取出等待的请求,以此完成所有的请求。
连接池
OkHttp通过连接池来实现TCP连接的复用。连接池维护着一个可复用的连接集合,并根据需要分配和释放这些连接。
当我们使用OkHttp发送一个网络请求时,OkHttp会首先从连接池中获取一个可用的连接。如果连接池中没有可用连接,或者获取到的连接不符合要求(比如已经过期),OkHttp会创建一个新的连接。获取到连接后,OkHttp会将请求发送给该连接进行网络通信
完成请求后,连接并不会立即关闭,而是会被放回连接池中以供复用。如果后续有新的请求需要发送,OkHttp会尝试从连接池中获取可用的连接,避免频繁地创建和关闭连接。
连接池还可以限制同时进行的连接数量,防止过多的连接占用系统资源。通过设置连接池的最大连接数,可以控制并发请求的数量,避免对服务器造成过大的负载。
需要注意的是,连接池会根据一定的策略来管理连接的过期和闲置时间,以保证连接的有效性和可复用性。默认情况下,OkHttp的连接池会根据服务器返回的Keep-Alive头信息来判断连接的存活时间。
OKHttp空闲连接如何清除
在将连接加入连接池时就会启动定时任务,有空闲连接的话,如果最长的空闲时间大于5分钟或空闲数大于5,就移除关闭这个最长空闲连接;如果空闲数不大于5且最长的空闲时间不大于5分钟,就返回到5分钟的剩余时间,然后等待这个时间再来清理。没有空闲连接就等5分钟后再尝试清理。没有连接则不清理。
OkHttp如何处理重定向
- 在OkHttp中,重定向是默认启用的。当服务器返回3xx状态码时,OkHttp会自动跟随重定向。重定向次数默认最多5次,超过次数会抛出异常。同时,OkHttp也支持SSL重定向,在HTTPS连接中进行重定向操作。如果需要禁用重定向,可以通过设置followRedirects(false)来实现。此外,OkHttp还提供了自定义重定向策略的能力,通过实现Redirect接口并传入相应的回调对象,可以根据需求对重定向进行灵活处理。
OkHttp如何处理网络超时
OkHttp提供了多种方式来处理网络请求的超时问题,包括连接超时、读取超时和写入超时。连接超时是指建立TCP连接时等待服务器响应的时间。可以通过connectTimeout()方法设置连接超时时间,默认为10秒。其次,读取超时是指从服务器读取数据的最大等待时间,可通过readTimeout()方法进行设置。默认也是10秒。最后,写入超时是指向服务器发送请求数据的最大等待时间,可以通过writeTimeout()方法进行设置。同样,默认为10秒。此外,OkHttp还提供了整个请求的超时时间控制,包括连接、读取和写入三个阶段。通过callTimeout()方法可以设置整个请求的最长超时时间。默认情况下,最长超时时间为10分钟。
如果需要对每个请求单独设置超时时间,可以使用自定义拦截器(Interceptor)来实现。通过在拦截器的intercept()方法中,根据请求信息设置相应的超时时间。
OkHttp的缓存机制是什么?
- OkHttp的缓存机制基于HTTP协议的缓存头字段,它支持两种缓存模式:有网络时使用网络数据、无网络时使用缓存数据;以及离线缓存模式。通过设置合适的缓存头字段,OkHttp能够判断是否可以使用缓存响应,从而减少网络请求次数,提高应用性能