OkHttp 是 Square 出品的 Android/Java 主流 HTTP 客户端,支持 HTTP/2、连接池、GZIP、缓存、重试;核心灵魂就是「拦截器链 Interceptor.Chain」
一、先一句话概括拦截器
拦截器采用责任链模式,请求按顺序逐个往下传递,直到最后一个拦截器真正发网络;响应原路反向回流,每个拦截器都能在「发请求前」改造 Request、「拿到响应后」改造 Response。
顺序:从上到下走 Request → 底层网络 → 从下往上回 Response
二、OkHttp 内置 5 个核心拦截器(顺序固定,必背!)
RealCall.getResponseWithInterceptorChain() 里组装的顺序:
RetryAndFollowUpInterceptor:重试、重定向(301/302、401 鉴权)
BridgeInterceptor:桥接,自动补全 HTTP 标准头(Content-Type、Accept-Encoding、gzip、Host 等)
CacheInterceptor:缓存逻辑,优先读本地缓存,遵循 HTTP 缓存协议(Cache-Control)
ConnectInterceptor:建立连接,从连接池拿可用 Socket 连接(HTTP/2 多路复用就在这里)
CallServerInterceptor:最终真正发包、收响应,底层 Socket IO,链的最后一站
📌 区分:
Application Interceptor(应用拦截器,我们 addInterceptor 添加):放在最开头,不走自动重试、重定向的子请求;适合打日志、统一加 token、参数、加密
Network Interceptor(网络拦截器,addNetworkInterceptor):放在 BridgeInterceptor 之后、CacheInterceptor 之前;能看到重定向 / 重试后的真实网络请求,可以篡改缓存相关 header
三、拦截器工作流程(重点,面试必讲)
核心接口:
kotlin
interface Interceptor {
fun intercept(chain: Chain): Response
}
chain.proceed(request) 就是放行、交给下一个拦截器
标准时序(非常关键)
自定义拦截器先执行【请求前置逻辑】:修改 Url、追加 Token、加公共 Header、打印请求日志
调用
chain.proceed(newRequest)→ 交给下一个拦截器(不调用 = 请求中断,直接返回自定义 Response)后面所有拦截器依次传递,直到 CallServerInterceptor 走 Socket 发出 HTTP 请求,拿到服务端 Response
Response 原路返回,回到当前拦截器
proceed()这一行之后,执行【响应后置逻辑】:解析、打印日志、统一错误处理、解密最终 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 网络拦截器(高频考题)
⚠️ 坑:应用拦截器只会收到初始请求一次;如果发生重试 / 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 上传大图 / 视频时,可以自定义拦截器:
统一添加鉴权 header
监控上传进度(拦截 ResponseBody 包装)
弱网下重试策略(配合 RetryAndFollowUpInterceptor)