一、核心设计思想
OkHttp 的核心架构是 "请求分发 + 拦截器链" 模式,主要基于以下几个设计模式:
| 设计模式 | 应用场景 |
|---|---|
| 建造者模式 | OkHttpClient 和 Request 的构建 |
| 门面模式 | OkHttpClient 作为统一入口,隐藏内部复杂性 |
| 责任链模式 | 拦截器链,将请求的发送者和接收者解耦 |
责任链模式是 OkHttp 的精髓------将网络请求的各个阶段封装到不同的拦截器中,串成一条链,请求沿着链依次传递,每个拦截器各司其职。
二、整体架构流程
#mermaid-svg-LFezjOWfC9vv4PLB{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-LFezjOWfC9vv4PLB .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-LFezjOWfC9vv4PLB .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-LFezjOWfC9vv4PLB .error-icon{fill:#552222;}#mermaid-svg-LFezjOWfC9vv4PLB .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-LFezjOWfC9vv4PLB .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-LFezjOWfC9vv4PLB .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-LFezjOWfC9vv4PLB .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-LFezjOWfC9vv4PLB .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-LFezjOWfC9vv4PLB .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-LFezjOWfC9vv4PLB .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-LFezjOWfC9vv4PLB .marker{fill:#333333;stroke:#333333;}#mermaid-svg-LFezjOWfC9vv4PLB .marker.cross{stroke:#333333;}#mermaid-svg-LFezjOWfC9vv4PLB svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-LFezjOWfC9vv4PLB p{margin:0;}#mermaid-svg-LFezjOWfC9vv4PLB .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-LFezjOWfC9vv4PLB .cluster-label text{fill:#333;}#mermaid-svg-LFezjOWfC9vv4PLB .cluster-label span{color:#333;}#mermaid-svg-LFezjOWfC9vv4PLB .cluster-label span p{background-color:transparent;}#mermaid-svg-LFezjOWfC9vv4PLB .label text,#mermaid-svg-LFezjOWfC9vv4PLB span{fill:#333;color:#333;}#mermaid-svg-LFezjOWfC9vv4PLB .node rect,#mermaid-svg-LFezjOWfC9vv4PLB .node circle,#mermaid-svg-LFezjOWfC9vv4PLB .node ellipse,#mermaid-svg-LFezjOWfC9vv4PLB .node polygon,#mermaid-svg-LFezjOWfC9vv4PLB .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-LFezjOWfC9vv4PLB .rough-node .label text,#mermaid-svg-LFezjOWfC9vv4PLB .node .label text,#mermaid-svg-LFezjOWfC9vv4PLB .image-shape .label,#mermaid-svg-LFezjOWfC9vv4PLB .icon-shape .label{text-anchor:middle;}#mermaid-svg-LFezjOWfC9vv4PLB .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-LFezjOWfC9vv4PLB .rough-node .label,#mermaid-svg-LFezjOWfC9vv4PLB .node .label,#mermaid-svg-LFezjOWfC9vv4PLB .image-shape .label,#mermaid-svg-LFezjOWfC9vv4PLB .icon-shape .label{text-align:center;}#mermaid-svg-LFezjOWfC9vv4PLB .node.clickable{cursor:pointer;}#mermaid-svg-LFezjOWfC9vv4PLB .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-LFezjOWfC9vv4PLB .arrowheadPath{fill:#333333;}#mermaid-svg-LFezjOWfC9vv4PLB .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-LFezjOWfC9vv4PLB .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-LFezjOWfC9vv4PLB .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-LFezjOWfC9vv4PLB .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-LFezjOWfC9vv4PLB .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-LFezjOWfC9vv4PLB .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-LFezjOWfC9vv4PLB .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-LFezjOWfC9vv4PLB .cluster text{fill:#333;}#mermaid-svg-LFezjOWfC9vv4PLB .cluster span{color:#333;}#mermaid-svg-LFezjOWfC9vv4PLB div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-LFezjOWfC9vv4PLB .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-LFezjOWfC9vv4PLB rect.text{fill:none;stroke-width:0;}#mermaid-svg-LFezjOWfC9vv4PLB .icon-shape,#mermaid-svg-LFezjOWfC9vv4PLB .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-LFezjOWfC9vv4PLB .icon-shape p,#mermaid-svg-LFezjOWfC9vv4PLB .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-LFezjOWfC9vv4PLB .icon-shape .label rect,#mermaid-svg-LFezjOWfC9vv4PLB .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-LFezjOWfC9vv4PLB .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-LFezjOWfC9vv4PLB .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-LFezjOWfC9vv4PLB :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 同步
异步
否
是
创建 OkHttpClient
构建 Request
client.newCall 创建 RealCall
请求类型
Call.execute
Call.enqueue
Dispatcher.executed
加入 runningSyncCalls
Dispatcher.enqueue
判断并发限制
是否超过
maxRequests=64 或
单Host=5?
加入 runningAsyncCalls
线程池执行
加入 readyAsyncCalls
等待队列
getResponseWithInterceptorChain
拦截器链处理
返回 Response
Dispatcher.finished
移除队列并调度等待任务
2.1 三个核心角色
使用 OkHttp 发起请求时,最少涉及三个角色:
OkHttpClient:全局配置容器(代理、SSL、超时、缓存等),建议作为单例Request:封装 URL、Header、Body 等请求信息Call(实际为RealCall):代表一个已准备好执行的请求,通过client.newCall(request)获得
2.2 Dispatcher(分发器)
Dispatcher 负责请求的调度管理,内部包含:
| 成员 | 说明 | 默认值 |
|---|---|---|
maxRequests |
最大并发请求数 | 64 |
maxRequestsPerHost |
单域名最大并发数 | 5 |
readyAsyncCalls |
异步等待队列 | --- |
runningAsyncCalls |
异步执行队列 | --- |
runningSyncCalls |
同步执行队列 | --- |
executorService |
线程池 | 类似 CachedThreadPool |
同步请求 :直接加入 runningSyncCalls 记录,由调用方线程执行。
异步请求 :判断是否超过并发限制------未超过则加入执行队列并提交线程池;超过则先进入等待队列。每次请求完成后,Dispatcher.finished() 会触发等待队列中的任务出队执行。
三、拦截器链(核心)
getResponseWithInterceptorChain() 是 OkHttp 最核心的方法,它按顺序构建拦截器列表:
#mermaid-svg-JheN8NU4X8R9uY5y{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-JheN8NU4X8R9uY5y .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-JheN8NU4X8R9uY5y .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-JheN8NU4X8R9uY5y .error-icon{fill:#552222;}#mermaid-svg-JheN8NU4X8R9uY5y .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-JheN8NU4X8R9uY5y .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-JheN8NU4X8R9uY5y .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-JheN8NU4X8R9uY5y .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-JheN8NU4X8R9uY5y .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-JheN8NU4X8R9uY5y .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-JheN8NU4X8R9uY5y .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-JheN8NU4X8R9uY5y .marker{fill:#333333;stroke:#333333;}#mermaid-svg-JheN8NU4X8R9uY5y .marker.cross{stroke:#333333;}#mermaid-svg-JheN8NU4X8R9uY5y svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-JheN8NU4X8R9uY5y p{margin:0;}#mermaid-svg-JheN8NU4X8R9uY5y .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-JheN8NU4X8R9uY5y .cluster-label text{fill:#333;}#mermaid-svg-JheN8NU4X8R9uY5y .cluster-label span{color:#333;}#mermaid-svg-JheN8NU4X8R9uY5y .cluster-label span p{background-color:transparent;}#mermaid-svg-JheN8NU4X8R9uY5y .label text,#mermaid-svg-JheN8NU4X8R9uY5y span{fill:#333;color:#333;}#mermaid-svg-JheN8NU4X8R9uY5y .node rect,#mermaid-svg-JheN8NU4X8R9uY5y .node circle,#mermaid-svg-JheN8NU4X8R9uY5y .node ellipse,#mermaid-svg-JheN8NU4X8R9uY5y .node polygon,#mermaid-svg-JheN8NU4X8R9uY5y .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-JheN8NU4X8R9uY5y .rough-node .label text,#mermaid-svg-JheN8NU4X8R9uY5y .node .label text,#mermaid-svg-JheN8NU4X8R9uY5y .image-shape .label,#mermaid-svg-JheN8NU4X8R9uY5y .icon-shape .label{text-anchor:middle;}#mermaid-svg-JheN8NU4X8R9uY5y .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-JheN8NU4X8R9uY5y .rough-node .label,#mermaid-svg-JheN8NU4X8R9uY5y .node .label,#mermaid-svg-JheN8NU4X8R9uY5y .image-shape .label,#mermaid-svg-JheN8NU4X8R9uY5y .icon-shape .label{text-align:center;}#mermaid-svg-JheN8NU4X8R9uY5y .node.clickable{cursor:pointer;}#mermaid-svg-JheN8NU4X8R9uY5y .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-JheN8NU4X8R9uY5y .arrowheadPath{fill:#333333;}#mermaid-svg-JheN8NU4X8R9uY5y .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-JheN8NU4X8R9uY5y .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-JheN8NU4X8R9uY5y .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-JheN8NU4X8R9uY5y .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-JheN8NU4X8R9uY5y .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-JheN8NU4X8R9uY5y .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-JheN8NU4X8R9uY5y .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-JheN8NU4X8R9uY5y .cluster text{fill:#333;}#mermaid-svg-JheN8NU4X8R9uY5y .cluster span{color:#333;}#mermaid-svg-JheN8NU4X8R9uY5y div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-JheN8NU4X8R9uY5y .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-JheN8NU4X8R9uY5y rect.text{fill:none;stroke-width:0;}#mermaid-svg-JheN8NU4X8R9uY5y .icon-shape,#mermaid-svg-JheN8NU4X8R9uY5y .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-JheN8NU4X8R9uY5y .icon-shape p,#mermaid-svg-JheN8NU4X8R9uY5y .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-JheN8NU4X8R9uY5y .icon-shape .label rect,#mermaid-svg-JheN8NU4X8R9uY5y .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-JheN8NU4X8R9uY5y .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-JheN8NU4X8R9uY5y .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-JheN8NU4X8R9uY5y :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 应用拦截器
client.interceptors
RetryAndFollowUpInterceptor
重试与重定向
BridgeInterceptor
请求/响应适配
CacheInterceptor
缓存处理
ConnectInterceptor
建立连接
网络拦截器
client.networkInterceptors
CallServerInterceptor
读写数据
3.1 各拦截器职责
| 拦截器 | 职责 |
|---|---|
| 应用拦截器(自定义) | 用户添加,最先执行,可处理公共参数、Header 等 |
| RetryAndFollowUpInterceptor | 连接失败自动重试、处理重定向 |
| BridgeInterceptor | 补全请求头(Content-Type、Content-Length、Host、Cookie 等),解压 GZIP 响应 |
| CacheInterceptor | 根据 HTTP 缓存策略,判断是否使用缓存 |
| ConnectInterceptor | 从连接池获取或新建 TCP 连接 |
| 网络拦截器(自定义) | 用户添加,在连接建立后、数据读写前执行,常用于监控网络层数据 |
| CallServerInterceptor | 最后一个拦截器,通过 HttpCodec 向服务器写出请求数据、读取响应数据 |
3.2 责任链传递机制
每个拦截器的 intercept(Chain chain) 方法分为三部分:
- 预处理:处理当前拦截器自身的逻辑
- 传递 :调用
chain.proceed(request)将请求交给下一个拦截器 - 后处理:下一个拦截器返回 Response 后的后续处理
四、连接池与连接复用
TCP 连接需要三次握手,开销较大。OkHttp 通过 连接池(ConnectionPool) 复用 TCP 连接来减少延迟。
#mermaid-svg-ZXWPaCjdiO4SQZrB{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-ZXWPaCjdiO4SQZrB .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-ZXWPaCjdiO4SQZrB .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-ZXWPaCjdiO4SQZrB .error-icon{fill:#552222;}#mermaid-svg-ZXWPaCjdiO4SQZrB .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-ZXWPaCjdiO4SQZrB .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-ZXWPaCjdiO4SQZrB .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-ZXWPaCjdiO4SQZrB .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-ZXWPaCjdiO4SQZrB .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-ZXWPaCjdiO4SQZrB .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-ZXWPaCjdiO4SQZrB .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-ZXWPaCjdiO4SQZrB .marker{fill:#333333;stroke:#333333;}#mermaid-svg-ZXWPaCjdiO4SQZrB .marker.cross{stroke:#333333;}#mermaid-svg-ZXWPaCjdiO4SQZrB svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-ZXWPaCjdiO4SQZrB p{margin:0;}#mermaid-svg-ZXWPaCjdiO4SQZrB .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-ZXWPaCjdiO4SQZrB .cluster-label text{fill:#333;}#mermaid-svg-ZXWPaCjdiO4SQZrB .cluster-label span{color:#333;}#mermaid-svg-ZXWPaCjdiO4SQZrB .cluster-label span p{background-color:transparent;}#mermaid-svg-ZXWPaCjdiO4SQZrB .label text,#mermaid-svg-ZXWPaCjdiO4SQZrB span{fill:#333;color:#333;}#mermaid-svg-ZXWPaCjdiO4SQZrB .node rect,#mermaid-svg-ZXWPaCjdiO4SQZrB .node circle,#mermaid-svg-ZXWPaCjdiO4SQZrB .node ellipse,#mermaid-svg-ZXWPaCjdiO4SQZrB .node polygon,#mermaid-svg-ZXWPaCjdiO4SQZrB .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-ZXWPaCjdiO4SQZrB .rough-node .label text,#mermaid-svg-ZXWPaCjdiO4SQZrB .node .label text,#mermaid-svg-ZXWPaCjdiO4SQZrB .image-shape .label,#mermaid-svg-ZXWPaCjdiO4SQZrB .icon-shape .label{text-anchor:middle;}#mermaid-svg-ZXWPaCjdiO4SQZrB .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-ZXWPaCjdiO4SQZrB .rough-node .label,#mermaid-svg-ZXWPaCjdiO4SQZrB .node .label,#mermaid-svg-ZXWPaCjdiO4SQZrB .image-shape .label,#mermaid-svg-ZXWPaCjdiO4SQZrB .icon-shape .label{text-align:center;}#mermaid-svg-ZXWPaCjdiO4SQZrB .node.clickable{cursor:pointer;}#mermaid-svg-ZXWPaCjdiO4SQZrB .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-ZXWPaCjdiO4SQZrB .arrowheadPath{fill:#333333;}#mermaid-svg-ZXWPaCjdiO4SQZrB .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-ZXWPaCjdiO4SQZrB .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-ZXWPaCjdiO4SQZrB .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ZXWPaCjdiO4SQZrB .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-ZXWPaCjdiO4SQZrB .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ZXWPaCjdiO4SQZrB .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-ZXWPaCjdiO4SQZrB .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-ZXWPaCjdiO4SQZrB .cluster text{fill:#333;}#mermaid-svg-ZXWPaCjdiO4SQZrB .cluster span{color:#333;}#mermaid-svg-ZXWPaCjdiO4SQZrB div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-ZXWPaCjdiO4SQZrB .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-ZXWPaCjdiO4SQZrB rect.text{fill:none;stroke-width:0;}#mermaid-svg-ZXWPaCjdiO4SQZrB .icon-shape,#mermaid-svg-ZXWPaCjdiO4SQZrB .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ZXWPaCjdiO4SQZrB .icon-shape p,#mermaid-svg-ZXWPaCjdiO4SQZrB .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-ZXWPaCjdiO4SQZrB .icon-shape .label rect,#mermaid-svg-ZXWPaCjdiO4SQZrB .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ZXWPaCjdiO4SQZrB .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-ZXWPaCjdiO4SQZrB .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-ZXWPaCjdiO4SQZrB :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 有
无
请求到达 ConnectInterceptor
根据 Address
查找可用连接
连接池中
是否有可用连接?
复用已有连接
创建新连接
TCP三次握手
存入连接池
执行请求
请求完成
连接归还连接池
不立即关闭
连接池清理线程
清理闲置连接
4.1 连接复用的关键点
Address:由 URL 的 Scheme、Host、Port 以及OkHttpClient的配置(如 HTTPS 设置)共同决定。相同Address的请求可共享同一个 Socket 连接。- 连接池策略:请求完成后连接不立即关闭,而是放回连接池供后续复用。
- 清理机制:连接池有后台清理线程,定期关闭闲置连接。
4.2 应用拦截器 vs 网络拦截器
面试常见问题:
| 应用拦截器 | 网络拦截器 | |
|---|---|---|
| 执行时机 | 最早执行,在重试和重定向之前 | 在 ConnectInterceptor 之后、CallServerInterceptor 之前 |
| 调用次数 | 只调用一次 | 可能调用多次(每次重试/重定向都会调用) |
| 适用场景 | 公共参数注入、日志打印 | 网络监控、流量统计 |
五、面试回答要点总结
回答"OkHttp 原理"时,可以按以下逻辑串联:
-
一句话概括 :OkHttp 基于责任链模式 ,通过拦截器链 处理请求的各个阶段,配合Dispatcher 调度请求,连接池复用 TCP 连接。
-
流程简述 :
OkHttpClient+Request→RealCall→execute()/enqueue()→Dispatcher调度 →getResponseWithInterceptorChain()→ 拦截器链依次处理 → 返回Response。 -
亮点展开(挑 1-2 个深入):
- 拦截器链:7 个拦截器的职责和顺序
- 连接池 :
Address决定连接复用,减少三次握手开销 - Dispatcher:并发控制(64/5)和线程池调度