OkHttp详解

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能够判断是否可以使用缓存响应,从而减少网络请求次数,提高应用性能
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值