详细理解OkHttp3中的拦截器4

在这里插入图片描述
OkHttp3是一个功能强大且灵活的HTTP客户端,它通过拦截器(Interceptor)提供了对HTTP请求和响应的全面控制。在这篇博客中,我们将详细介绍OkHttp3中的拦截器,解析其工作原理、分类、实际应用及源码分析。

什么是拦截器?🔍

拦截器是OkHttp3中的一个重要机制,它允许开发者在HTTP请求和响应的各个阶段进行自定义处理。通过拦截器,可以实现如日志记录、请求重试、响应缓存等功能。

拦截器的分类 📋

OkHttp3中有两种类型的拦截器:应用拦截器和网络拦截器。

应用拦截器 🏢

应用拦截器主要用于应用级的处理,它们在整个请求过程的最外层。应用拦截器可以添加、删除或修改请求和响应,甚至可以短路请求,直接返回自定义响应。

网络拦截器 🌐

网络拦截器用于在网络层处理请求和响应,它们只能处理真正发出的请求和接收到的响应。网络拦截器无法短路请求,也无法影响缓存的处理。

拦截器的工作原理 🛠️

拦截器通过责任链模式(Chain of Responsibility)来处理HTTP请求。每个拦截器都持有一个拦截链(Interceptor.Chain)对象,通过调用chain.proceed(request)将请求传递给下一个拦截器。
在这里插入图片描述

@startuml
actor Client
participant "OkHttpClient" as OkHttpClient
participant "Interceptor" as Interceptor
participant "Interceptor.Chain" as Chain
participant "Network" as Network

Client -> OkHttpClient : new Call(request)
OkHttpClient -> Interceptor : intercept(request)
Interceptor -> Chain : chain.proceed(request)
Chain -> Network : send request
Network -> Chain : receive response
Chain -> Interceptor : return response
Interceptor -> OkHttpClient : return response
OkHttpClient -> Client : response
@enduml

如何实现拦截器?📝

实现一个拦截器非常简单,只需实现Interceptor接口并重写intercept方法。

public class LoggingInterceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();

        long t1 = System.nanoTime();
        System.out.println(String.format("Sending request %s on %s%n%s",
            request.url(), chain.connection(), request.headers()));

        Response response = chain.proceed(request);

        long t2 = System.nanoTime();
        System.out.println(String.format("Received response for %s in %.1fms%n%s",
            response.request().url(), (t2 - t1) / 1e6d, response.headers()));

        return response;
    }
}

在这个例子中,LoggingInterceptor打印了请求和响应的详细信息。我们可以通过在OkHttpClient中添加这个拦截器来使用它。

使用拦截器 📦

在OkHttpClient中添加拦截器非常简单。可以通过addInterceptor方法添加应用拦截器,通过addNetworkInterceptor方法添加网络拦截器。

OkHttpClient client = new OkHttpClient.Builder()
    .addInterceptor(new LoggingInterceptor())
    .addNetworkInterceptor(new StethoInterceptor())
    .build();

拦截器的实际应用 💡

拦截器的应用非常广泛,下面是几个常见的用例。

日志记录 📄

日志拦截器可以记录每个请求和响应的详细信息,便于调试和分析。

public class LoggingInterceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();

        long t1 = System.nanoTime();
        System.out.println(String.format("Sending request %s on %s%n%s",
            request.url(), chain.connection(), request.headers()));

        Response response = chain.proceed(request);

        long t2 = System.nanoTime();
        System.out.println(String.format("Received response for %s in %.1fms%n%s",
            response.request().url(), (t2 - t1) / 1e6d, response.headers()));

        return response;
    }
}

请求重试 🔄

请求重试拦截器可以在请求失败时自动重试,提高请求的可靠性。

public class RetryInterceptor implements Interceptor {
    private int maxRetries;

    public RetryInterceptor(int maxRetries) {
        this.maxRetries = maxRetries;
    }

    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        Response response = chain.proceed(request);
        int tryCount = 0;

        while (!response.isSuccessful() && tryCount < maxRetries) {
            tryCount++;
            response = chain.proceed(request);
        }

        return response;
    }
}

缓存处理 📦

缓存拦截器可以根据响应的缓存头对请求进行缓存处理,减少网络请求次数。

public class CacheInterceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();

        // Use the cache data if available
        if (!isNetworkAvailable()) {
            request = request.newBuilder()
                .cacheControl(CacheControl.FORCE_CACHE)
                .build();
        }

        Response response = chain.proceed(request);

        // Modify response to use cache data if necessary
        if (isNetworkAvailable()) {
            response = response.newBuilder()
                .header("Cache-Control", "public, max-age=" + 60)
                .removeHeader("Pragma")
                .build();
        } else {
            response = response.newBuilder()
                .header("Cache-Control", "public, only-if-cached, max-stale=" + 60 * 60 * 24)
                .removeHeader("Pragma")
                .build();
        }

        return response;
    }
}

源码解读 🔍

下面我们将通过阅读源码,深入理解OkHttp3中拦截器的实现。

Interceptor接口定义

public interface Interceptor {
    Response intercept(Chain chain) throws IOException;

    interface Chain {
        Request request();
        Response proceed(Request request) throws IOException;
        Connection connection();
    }
}

Interceptor接口只有一个方法intercept,这个方法接收一个Chain对象。Chain接口定义了三个方法:

  • request():返回当前的请求。
  • proceed(Request request):将请求传递给下一个拦截器。
  • connection():返回当前的连接。

RealInterceptorChain

RealInterceptorChain类是Interceptor.Chain接口的实现,它负责真正的请求处理和拦截器链的管理。

final class RealInterceptorChain implements Interceptor.Chain {
    private final List<Interceptor> interceptors;
    private final int index;
    private final Request request;

    RealInterceptorChain(List<Interceptor> interceptors, int index, Request request) {
        this.interceptors = interceptors

;
        this.index = index;
        this.request = request;
    }

    @Override public Request request() {
        return request;
    }

    @Override public Response proceed(Request request) throws IOException {
        // Call the next interceptor in the chain.
        RealInterceptorChain next = new RealInterceptorChain(interceptors, index + 1, request);
        Interceptor interceptor = interceptors.get(index);
        Response response = interceptor.intercept(next);
        return response;
    }

    @Override public Connection connection() {
        return null;
    }
}

RealInterceptorChain中,proceed方法创建了一个新的RealInterceptorChain实例,并调用下一个拦截器的intercept方法。这样就形成了一个拦截器链,每个拦截器依次处理请求。

拦截器流程示意图 📊

我们可以用下面的流程图来表示拦截器的处理流程。

详细理解OkHttp3中的拦截器

@startuml
start
:创建 OkHttpClient;
:添加拦截器;
:构建请求;
:执行请求;

while (有下一个拦截器?) is (是)
    :调用下一个拦截器的 intercept 方法;
endwhile (否)

:发送网络请求;
:接收响应;

while (有上一个拦截器?) is (是)
    :返回响应给上一个拦截器;
endwhile (否)

:返回响应给 OkHttpClient;
:返回响应给调用者;
stop
@enduml

总结 🏁

拦截器是OkHttp3中的一个强大功能,它提供了对HTTP请求和响应的全面控制。通过拦截器,我们可以实现各种自定义逻辑,从而提高应用的灵活性和可维护性。在实际开发中,合理使用拦截器可以极大地优化我们的网络请求处理流程。

Best Regards!

  • 24
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

jiet_h

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值