Android OkHttp Interceptor

Android OkHttp Interceptor

  • 采用了责任链模式,拦截器链是一个有序的拦截器集合,请求和响应会依次经过每个拦截器,拦截器允许在请求和响应的过程中插入自定义逻辑
  • OkHttp 提供了两种不同层级的拦截器:Application Interceptor 应用拦截器和 Network Interceptor 网络拦截器
  • Application Interceptor 执行频率更高(无论是否走网络),需要注意避免耗时操作阻塞主线程

Application Interceptor 应用拦截器

  • 位于整个请求链的最前端,在请求被发送到网络之前(可能处理缓存响应,比如命中缓存时直接返回,不触发网络请求)和响应返回到应用程序之后进行拦截(能拦截所有请求,无法获取底层网络连接 Connection 对象)
  • 每次请求只调用一次,不处理重定向、重试等等中间过程
  • 通过 addInterceptor 添加
  • 应用:统一添加公共请求头(比如统一添加 Token)、统一处理响应(比如 401 Token 令牌过期)、全局错误码处理、统一进行请求响应日志打印记录和统一加密解密等
java 复制代码
//为所有请求添加 Authorization 头
OkHttpClient okHttpClient = new OkHttpClient.Builder()
    .addInterceptor(new Interceptor() {
        @Override
        public Response intercept(Chain chain) throws IOException {
            Request request = chain.request().newBuilder()
                .addHeader("Accept", "application/json")
                .addHeader("Content-Type", "application/json")
                .addHeader("Authorization", "Bearer token")
                .build();
            return chain.proceed(request);
        }
    })
    .build();
java 复制代码
//统一处理响应的头信息
OkHttpClient okHttpClient = new OkHttpClient.Builder()
    .addInterceptor(new Interceptor() {
        @Override
        public Response intercept(Chain chain) throws IOException {
            Response response = chain.proceed(chain.request());
            String traceId = response.header("traceId");
            System.out.println("响应 traceId: " + traceId);
            return response;
        }
    })
    .build();
java 复制代码
//全局错误码处理
public class ErrorHandleInterceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request().newBuilder()
            .addHeader("Authorization", "Bearer " + getToken()) //从本地获取 Token
            .build();
        Response response = chain.proceed(request);
        //Response response = chain.proceed(chain.request());
        if (response.code() == 401) {
            //重新获取 Token 并重试请求
            refreshToken();
            Request newRequest = request.newBuilder()
                .header("Authorization", "Bearer " + getToken())
                .build();
            return chain.proceed(newRequest);
        }
        return response;
    }
}
OkHttpClient okHttpClient = new OkHttpClient.Builder()
    .addInterceptor(new ErrorHandleInterceptor())
    .build();
java 复制代码
//统一进行日志打印记录
HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor();
httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);

OkHttpClient okHttpClient = new OkHttpClient.Builder()
    .addInterceptor(httpLoggingInterceptor)
    .build();

Network Interceptor 网络拦截器

  • 在请求实际被发送到网络前和响应从网络返回后进行拦截(不处理缓存响应,仅能拦截实际发送到网络的请求,能访问底层网络连接 Connection 对象,获取 TLS 协议、IP 等底层信息)
  • 每次网络请求都可能调用(包括重试、重定向)
  • 通过 addNetworkInterceptor 添加
  • 应用:网络调试(查看网络请求和响应的原始数据)、网络性能监控(监控耗时)和拦截重试(根据网络状态自动重试请求)
java 复制代码
class NetworkLoggingInterceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        long startTime = System.nanoTime();
        Request request = chain.request();
        //获取连接信息(仅网络拦截器可用)
        Connection connection = chain.connection();
        if (connection != null) {
            Socket socket = connection.socket();
            String host = socket.getInetAddress().getHostAddress();
            Log.d("Network", "Request url=" + request.url() + " host=" + host);
        }
        Response response = chain.proceed(request);
        long endTime = System.nanoTime();
        Log.d("Network", "diffTime: " + (endTime - startTime) + " ns");
        return response;
    }
}
OkHttpClient okHttpClient = new OkHttpClient.Builder()
    .addNetworkInterceptor(new NetworkLoggingInterceptor())
    .build();

拦截器执行顺序

  • 请求顺序:
    • 所有自定义 Application Interceptor 应用拦截器按添加顺序依次执行(应用拦截器是最先执行的拦截器)
    • 内置拦截器 RetryAndFollowUpInterceptor 重试和重定向拦截器,处理请求重定向(比如 30X 响应码,重定向时直接发起新的请求)和网络请求失败后进行重试,通过 while 死循环实现多次尝试
    • 内置拦截器 BridgeInterceptor 桥接拦截器,作为应用层与网络层的桥梁,自动为请求添加必要头信息(比如 Content-Type、Cookie、Host 和 User-Agent 等),设置 Connection 支持 Keep-Alive,并移除响应中的临时头,设置 Accept-Encoding 支持 gzip 压缩传输,并且在接收到内容后进行解压
    • 内置拦截器 CacheInterceptor 缓存拦截器,管理 HTTP 缓存逻辑,优先返回缓存响应(倘若命中了缓存,那就意味着不需要往下继续走网络请求了,所以后续就不会执行网络拦截器了),否则触发网络请求并更新缓存
    • 内置拦截器 ConnectInterceptor 连接拦截器,负责与服务器建立 TCP 连接,为后续请求准备网络通道
    • 所有自定义 Network Interceptor 网络拦截器按添加顺序依次执行(网络拦截器位于内置拦截器 ConnectInterceptor 和内置拦截器 CallServerInterceptor 之间)
    • 内置拦截器 CallServerInterceptor 网络请求,拦截器链的最后一环,发送最终请求至服务器并获取原始响应(向服务器发起真正的访问请求,获取 Response)
  • 响应顺序:
    • 返回响应给自定义 Network Interceptor 网络拦截器按添加顺序逆序处理
    • 返回响应给自定义 Application Interceptor 应用拦截器按添加顺序逆序处理

总结

  • Application Interceptor 应用拦截器:用于业务逻辑处理(认证、日志和错误处理等),避免耗时操作
  • Network Interceptor 网络拦截器:用于网络层面的处理(压缩、加密和网络监控等),可能被多次调用
  • 执行顺序:多个 Application Interceptor 按添加顺序执行,Network Interceptor 在 Application Interceptor 之后执行,正因为应用拦截器在 RetryAndFollowUpInterceptor 之前,所以一旦发生错误重试或网络重定向,网络拦截器可能会执行多次(因为相当于进行了二次请求),而应用拦截器只走了一次
相关推荐
来来走走35 分钟前
Flutter开发 webview_flutter的基本使用
android·flutter
Jerry说前后端1 小时前
Android 组件封装实践:从解耦到架构演进
android·前端·架构
大王派来巡山的小旋风2 小时前
Kotlin基本用法三
android·kotlin
Jerry说前后端3 小时前
Android 移动端 UI 设计:前端常用设计原则总结
android·前端·ui
bytebeats3 小时前
Jetpack Compose 1.9: 核心新特性简介
android·android jetpack
Icey_World3 小时前
Mysql笔记-错误条件\处理程序
android
大王派来巡山的小旋风4 小时前
Kotlin基本用法之集合(一)
android·程序员·kotlin
用户2018792831674 小时前
智能广播系统(RemoteCallbackList)的诞生
android
用户2018792831675 小时前
Binder 同应用内(本地)通信是否存在 1MB 大小限制?
android