Administrator
发布于 2026-08-12 / 144 阅读
0
0

介绍下 okhttp,拦截器是怎么工作的?

OkHttp 是 Square 出品的 Android/Java 主流 HTTP 客户端,支持 HTTP/2、连接池、GZIP、缓存、重试;核心灵魂就是「拦截器链 Interceptor.Chain」

一、先一句话概括拦截器

拦截器采用责任链模式,请求按顺序逐个往下传递,直到最后一个拦截器真正发网络;响应原路反向回流,每个拦截器都能在「发请求前」改造 Request、「拿到响应后」改造 Response。

顺序:从上到下走 Request → 底层网络 → 从下往上回 Response

二、OkHttp 内置 5 个核心拦截器(顺序固定,必背!)

RealCall.getResponseWithInterceptorChain() 里组装的顺序:

  1. RetryAndFollowUpInterceptor:重试、重定向(301/302、401 鉴权)

  2. BridgeInterceptor:桥接,自动补全 HTTP 标准头(Content-Type、Accept-Encoding、gzip、Host 等)

  3. CacheInterceptor:缓存逻辑,优先读本地缓存,遵循 HTTP 缓存协议(Cache-Control)

  4. ConnectInterceptor:建立连接,从连接池拿可用 Socket 连接(HTTP/2 多路复用就在这里)

  5. CallServerInterceptor:最终真正发包、收响应,底层 Socket IO,链的最后一站

📌 区分:

  • Application Interceptor(应用拦截器,我们 addInterceptor 添加):放在最开头,不走自动重试、重定向的子请求;适合打日志、统一加 token、参数、加密

  • Network Interceptor(网络拦截器,addNetworkInterceptor):放在 BridgeInterceptor 之后、CacheInterceptor 之前;能看到重定向 / 重试后的真实网络请求,可以篡改缓存相关 header

三、拦截器工作流程(重点,面试必讲)

核心接口:

kotlin

interface Interceptor {
  fun intercept(chain: Chain): Response
}

chain.proceed(request) 就是放行、交给下一个拦截器

标准时序(非常关键)

  1. 自定义拦截器先执行【请求前置逻辑】:修改 Url、追加 Token、加公共 Header、打印请求日志

  2. 调用 chain.proceed(newRequest) → 交给下一个拦截器(不调用 = 请求中断,直接返回自定义 Response)

  3. 后面所有拦截器依次传递,直到 CallServerInterceptor 走 Socket 发出 HTTP 请求,拿到服务端 Response

  4. Response 原路返回,回到当前拦截器 proceed() 这一行之后,执行【响应后置逻辑】:解析、打印日志、统一错误处理、解密

  5. 最终 Response 回到上层业务

✅ 形象比喻:快递流水线

Request = 快递包裹,一层层往下传;最底层 CallServerInterceptor 是发货站点;Response 是回执原路一层层回来。每个拦截器既能打包 / 拆包,也可以直接拦截不往下发

极简伪代码演示

kotlin

class TokenInterceptor : Interceptor {
    override fun intercept(chain: Interceptor.Chain): Response {
        // ========== 请求前(下行)==========
        val oldReq = chain.request()
        val newReq = oldReq.newBuilder()
            .header("token", "xxxx")
            .build()

        // 放行,交给下一环,阻塞等待网络返回response
        val response = chain.proceed(newReq)

        // ========== 响应后(上行,回来的时候)==========
        return response
    }
}

四、应用拦截器 vs 网络拦截器(高频考题)

addInterceptor 应用拦截器

addNetworkInterceptor 网络拦截器

执行位置

整个拦截器链最头部

Bridge 之后、Cache 之前

是否感知重试 / 重定向

❌ 不会收到重试后的多次请求

✅ 每次真实网络发包都会触发

能不能修改缓存 Header

不推荐

✅ 适合修改缓存相关头

典型用途

统一 Token、日志、请求加密、全局异常

抓真实网络包、篡改缓存策略、监控真实流量

⚠️ 坑:应用拦截器只会收到初始请求一次;如果发生重试 / 302 重定向,内部会多次走网络拦截器,应用拦截器不会重复执行!

五、面试【1 分钟口述标准答案(直接背)】

OkHttp 拦截器基于责任链模式,整条链按顺序传递 Request,到最底层 CallServerInterceptor 完成 Socket 网络通信,然后 Response 原路回流。

OkHttp 内置 5 个拦截器,依次负责重试重定向、补全 HTTP 头、HTTP 缓存、获取连接池 Socket、最终收发网络数据。

我们自定义拦截器分两种:应用拦截器 addInterceptor 放在链最前面,适合统一添加 token、日志;网络拦截器 addNetworkInterceptor 能感知重试、重定向产生的真实网络请求。

在 intercept 方法里,chain.proceed() 就是放行到下一环;proceed 之前处理 Request,拿到返回的 Response 之后做响应处理;如果不调用 proceed,直接返回 Response,就能直接拦截、不发起真实网络请求。

六、高频连环追问(准备好)

Q1:chain.proceed 里面做了什么?

拿到下一个拦截器,构造新 Chain,调用下一个 intercept (),形成递归链式调用,直到 CallServerInterceptor 执行 Socket IO。

Q2:拦截器可以中断请求吗?

可以,不调用 chain.proceed (),直接构造 Response 返回,直接短路,不会走到真实网络。适合本地 mock、权限拦截。

Q3:连接池是在哪个拦截器处理?

ConnectInterceptor,负责从 RealConnectionPool 拿复用 Socket,实现 HTTP/2 多路复用、TCP 长连接复用,减少握手开销。

Q4:BridgeInterceptor 干了啥?

补全标准 HTTP 请求头:Host、Content-Length、Accept-Encoding (gzip)、User-Agent;收到响应后自动 gzip 解压缩。

Q5:CacheInterceptor 缓存原理?

读取 / 写入本地缓存,根据 Cache-Control、If-Modified-Since 等 HTTP 标准协商缓存,命中缓存直接返回、不走网络。

七、加分延伸(贴合你的 Android 影像岗)

影像 App 上传大图 / 视频时,可以自定义拦截器:

  1. 统一添加鉴权 header

  2. 监控上传进度(拦截 ResponseBody 包装)

  3. 弱网下重试策略(配合 RetryAndFollowUpInterceptor)


评论