1. 整体架构解析:责任链模式、注册顺序与请求流转

1.1 原理:责任链模式与 Interceptor 接口

OkHttp 的拦截器链基于经典责任链模式(Chain of Responsibility)设计。在该模式下,每个拦截器独立处理请求/响应,并决定是否将任务传递给链中的下一个节点。这种设计让网络层具备高度可插拔性——增删一个拦截器不影响其他环节。

核心接口定义:Interceptor 是链中的基本单元,Chain 负责维护链式调用状态。
// Interceptor 接口(OkHttp 4.x / OkHttp 3.x 相同)
public interface Interceptor {
    Response intercept(Chain chain) throws IOException;

    interface Chain {
        Request request();
        Response proceed(Request request) throws IOException;
        Connection connection();
        Call call();
        int connectTimeoutMillis();
        Chain withConnectTimeout(int timeout, TimeUnit unit);
        int readTimeoutMillis();
        Chain withReadTimeout(int timeout, TimeUnit unit);
        int writeTimeoutMillis();
        Chain withWriteTimeout(int timeout, TimeUnit unit);
    }
}

每个拦截器在 intercept() 中既可以预处理请求(添加头、修改 body),也可以后处理响应(解压缩、缓存写入)。关键规则:必须调用 chain.proceed(request) 才能将请求传递给下一拦截器,否则链会中断。

1.2 拦截器注册顺序与分类

OkHttp 支持两类拦截器,注册 API 不同,在链中的位置也不同:

拦截器类型注册方法链中位置典型用途
应用层拦截器addInterceptor()位于 RetryAndFollowUpInterceptor 之前统一加签、日志、请求头注入
网络层拦截器addNetworkInterceptor()位于 ConnectInterceptor 之后,靠近实际网络 I/O重试、重定向、网络级监控

内置拦截器的固定注册顺序(不可调换)如下表所示,该顺序决定了请求/响应的处理流水线:

序号拦截器职责是否可跳过
1应用层拦截器(用户自定义)全局预处理/后处理,如统一 Header、请求加密—(用户控制)
2RetryAndFollowUpInterceptor连接失败重试、3xx 重定向跟随否(核心稳定)
3BridgeInterceptor补充请求头(Content-Type、Content-Length、Host 等),解压 gzip否
4CacheInterceptor缓存命中直接返回,未命中写缓存可移除
5ConnectInterceptor建立 TCP / TLS 连接,复用连接池否
6网络层拦截器(用户自定义)网络级监控、Mock、网络日志—(用户控制)
实践建议:应用层拦截器适合做业务语义的处理(如 刷新、参数签名);网络层拦截器适合做网络诊断(如抓包、模拟弱网)。不要将业务逻辑混入网络层拦截器,否则重试时会重复执行。

1.3 请求与响应流转过程

一次完整的 HTTP 请求在拦截器链中经历两次贯穿:

  1. 请求下行(Request → Server):从链首逐层穿透到链尾,每个拦截器可修改请求、添加 header、重试逻辑。
  2. 响应上行(Server → Request):从链尾逐层回溯到链首,每个拦截器可处理响应、解压缩、缓存写入。

流转的核心是 RealInterceptorChain 的 proceed() 方法,它通过递归/迭代索引驱动链前进:

// RealInterceptorChain.proceed() 简化逻辑
public Response proceed(Request request, StreamAllocation streamAllocation, ...) throws IOException {
    if (index >= interceptors.size()) throw new AssertionError();
    calls++;
    // 创建下一个链节点,index + 1
    RealInterceptorChain next = new RealInterceptorChain(
            interceptors, streamAllocation, ... , index + 1, request);
    // 获取当前拦截器并执行
    Interceptor interceptor = interceptors.get(index);
    Response response = interceptor.intercept(next);
    return response;
}

每个拦截器调用 chain.proceed(request) 时,链索引 +1,递归进入下一拦截器;当所有拦截器执行完毕,proceed() 返回最终响应,再逐层回溯。

常见错误:如果在 intercept() 中没有调用 chain.proceed(),请求将永远无法到达服务器,且链中后续拦截器全部失效。此时 intercept() 必须自己构造并返回一个 Response 对象,否则抛出 NullPointerException。

1.4 核心 API 与配置示例

构建 OkHttpClient 时注册拦截器:

// 应用层拦截器
Interceptor appInterceptor = new Interceptor() {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request original = chain.request();
        // 预处理:添加 
        Request modified = original.newBuilder()
                .header("Authorization", "Bearer " + )
                .build();
        // 传递给下一拦截器
        Response response = chain.proceed(modified);
        // 后处理:记录响应状态
        return response;
    }
};

// 网络层拦截器
Interceptor netInterceptor = new Interceptor() {
    @Override
    public Response intercept(Chain chain) throws IOException {
        // 仅记录网络往返耗时
        long start = System.nanoTime();
        Response response = chain.proceed(chain.request());
        long elapsed = System.nanoTime() - start;
        System.out.println("Network round-trip: " + elapsed / 1_000_000 + " ms");
        return response;
    }
};

// 注册到 OkHttpClient
OkHttpClient client = new OkHttpClient.Builder()
        .addInterceptor(appInterceptor)          // 应用层
        .addNetworkInterceptor(netInterceptor)   // 网络层
        .build();
调试技巧:在开发阶段,使用 HttpLoggingInterceptor(需引入 logging-interceptor 依赖)打印完整的请求/响应报文。设置 level = BODY 可看到 header 与 body 细节。
// 引入依赖:implementation("com.squareup.okhttp3:logging-interceptor:4.12.0")
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient.Builder()
        .addInterceptor(logging)
        .build();

1.5 常见错误与避坑

错误场景现象根因解决方案
拦截器未执行自定义逻辑完全没生效拦截器未通过 addInterceptor() / addNetworkInterceptor() 注册检查 Builder 链中是否添加
请求卡死 / 超时请求无响应,最终抛 SocketTimeoutException拦截器内未调用 chain.proceed()确保每个拦截器都调用了 proceed() 或返回合法 Response
响应数据异常响应体为空或乱码拦截器多次调用 proceed() 导致流被消费每个拦截器只调用一次 proceed(),缓存 Response body
顺序不符合预期应用层逻辑在重试后未再次执行把业务逻辑放在了网络层拦截器业务逻辑应放在应用层拦截器,网络层只做网络级处理

1.6 性能与稳定性优化要点

  • 避免耗时操作:拦截器运行在 OkHttp 的调度线程中,不要做数据库读写、大规模 JSON 解析、同步网络请求。必要时应使用异步回调或切换线程。
  • 控制拦截器数量:每增加一个拦截器就多一次方法调用和对象创建。生产环境建议应用层拦截器 ≤ 3 个,网络层拦截器 ≤ 2 个。
  • 复用连接池:ConnectInterceptor 依赖 ConnectionPool,自定义拦截器不要关闭或污染连接,避免连接泄漏。
  • 缓存策略:CacheInterceptor 配合 Cache 对象可大幅减少重复请求。设置合理的 maxAge 和 maxStale 避免缓存雪崩。
  • 监控与熔断:在网络层拦截器中集成失败率监控,当错误率超过阈值时快速失败(断路器模式),防止下游故障拖垮客户端。
OkHttp 拦截器链请求 → 响应流转图 请求入口 应用层拦截器 RetryAndFollowUp BridgeInterceptor CacheInterceptor ConnectInterceptor 网络层拦截器 服务器 图例说明 🔹 左侧蓝色箭头:请求沿链自顶向下传递,每个拦截器可修改请求 🔹 右侧绿色箭头:响应沿链自底向上回溯,每个拦截器可处理响应 🔸 必须调用 chain.proceed() 才能进入下一节点 🔸 任一拦截器不调用 proceed() 则链中断