OkHttp 与 Retrofit(流式请求和普通请求)
OkHttp 与 Retrofit 详解
概述
在 Java/Android 开发中,OkHttp 和 Retrofit 是两个最核心的 HTTP 客户端库。它们经常一起使用,但职责不同:
- OkHttp:底层 HTTP 客户端,负责实际的网络通信
- Retrofit:REST API 封装层,基于 OkHttp,提供声明式的 API 调用方式
一、HTTP 请求的基本流程
在深入理解这两个库之前,先了解一下 HTTP 请求的基本流程:
客户端 服务器
│ │
│ ────── 建立 TCP 连接 ──────→ │
│ │
│ ────── 发送请求 ─────────→ │
│ method: POST │
│ url: /v1/chat/completions │
│ headers: Authorization... │
│ body: {"model":"gpt-3.5"...}│
│ │
│ ←────── 接收响应 ───────── │
│ status: 200 │
│ headers: Content-Type... │
│ body: {"id":"chatcmpl-..."} │
│ │
│ ────── 关闭连接 ───────────→ │
HTTP 客户端库的作用就是帮你处理这个流程的所有细节。
二、OkHttp 详解
2.1 什么是 OkHttp?
OkHttp 是 Square 公司开源的高性能 HTTP 客户端库,是 Android/Java 生态中最流行的 HTTP 框架。
- 官网:https://square.github.io/okhttp/
- Maven 依赖:
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.12.0</version>
</dependency>
2.2 核心概念
| 类名 | 作用 |
|---|---|
OkHttpClient |
HTTP 客户端实例,管理连接池、超时、拦截器等配置 |
Request |
请求对象,包含 URL、Method、Headers、Body |
RequestBody |
请求体,用于 POST/PUT 请求 |
Response |
响应对象,包含状态码、Headers、Body |
Call |
一次请求任务,可以同步执行或异步执行 |
Interceptor |
拦截器,在请求前后进行处理 |
2.3 基本用法
同步 GET 请求
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("https://api.openai.com/v1/models")
.header("Authorization", "Bearer sk-xxx")
.build();
Response response = client.newCall(request).execute();
String body = response.body().string();
同步 POST 请求
MediaType JSON = MediaType.parse("application/json");
RequestBody body = RequestBody.create(JSON, "{\"key\":\"value\"}");
Request request = new Request.Builder()
.url("https://api.openai.com/v1/chat/completions")
.header("Content-Type", "application/json")
.header("Authorization", "Bearer sk-xxx")
.post(body)
.build();
Response response = client.newCall(request).execute();
异步请求
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
// 请求失败
}
@Override
public void onResponse(Call call, Response response) throws IOException {
String body = response.body().string();
// 处理响应
}
});
2.4 拦截器机制(核心扩展点)
拦截器是 OkHttp 最强大的特性,可以在请求发出前和响应返回后进行处理:
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(chain -> {
// 1. 请求发出前处理
Request originalRequest = chain.request();
System.out.println("请求URL: " + originalRequest.url());
// 2. 继续执行请求
Response response = chain.proceed(originalRequest);
// 3. 响应返回后处理
System.out.println("响应状态: " + response.code());
return response;
})
.build();
拦截器执行顺序:
请求
│
▼
┌─────────────────┐
│ 应用拦截器 1 │ ← 添加认证、日志等
└────────┬────────┘
▼
┌─────────────────┐
│ 应用拦截器 2 │
└────────┬────────┘
▼
┌─────────────────┐
│ OkHttp 核心 │ ← 连接池、重试、缓存
└────────┬────────┘
▼
┌─────────────────┐
│ 网络拦截器 │ ← 处理网络层
└────────┬────────┘
▼
网络请求
2.5 常用配置
OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(30, TimeUnit.SECONDS) // 连接超时
.readTimeout(30, TimeUnit.SECONDS) // 读取超时
.writeTimeout(30, TimeUnit.SECONDS) // 写入超时
.retryOnConnectionFailure(true) // 连接失败重试
.addInterceptor(new HttpLoggingInterceptor()) // 日志拦截器
.addInterceptor(new AuthInterceptor()) // 认证拦截器
.build();
2.6 OkHttp 的优势
| 特性 | 说明 |
|---|---|
| 连接池 | 复用 TCP 连接,减少握手延迟 |
| GZIP 压缩 | 自动处理请求体压缩/解压 |
| HTTP 缓存 | 支持响应缓存,减少重复请求 |
| WebSocket | 支持长连接双向通信 |
| SSE | 支持 Server-Sent Events(流式响应) |
| 拦截器链 | 灵活的请求/响应处理机制 |
三、Retrofit 详解
3.1 什么是 Retrofit?
Retrofit 是 Square 公司开源的 REST 客户端库,基于 OkHttp 构建,专注于简化 RESTful API 调用。
- 官网:https://square.github.io/retrofit/
- Maven 依赖:
<dependency>
<groupId>com.squareup.retrofit2</groupId>
<artifactId>retrofit</artifactId>
<version>2.9.0</version>
</dependency>
3.2 核心思想
传统方式(手动处理):
// 需要手动构造请求、解析响应
String json = "{\"model\":\"gpt-3.5-turbo\"}";
RequestBody body = RequestBody.create(JSON, json);
Request request = new Request.Builder()
.url("https://api.openai.com/v1/chat/completions")
.post(body)
.build();
Response response = client.newCall(request).execute();
ChatResponse resp = objectMapper.readValue(response.body().string(), ChatResponse.class);
使用 Retrofit(声明式):
// 1. 定义接口
public interface OpenAiApi {
@POST("v1/chat/completions")
Call<ChatResponse> completions(@Body ChatRequest request);
}
// 2. 创建实例
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.openai.com/")
.build();
OpenAiApi api = retrofit.create(OpenAiApi.class);
// 3. 调用就像调用本地方法
ChatResponse resp = api.completions(request).execute().body();
3.3 工作原理(动态代理)
Retrofit 使用 JDK 动态代理 实现接口方法到 HTTP 请求的转换:
// 当你调用 api.completions(request) 时
ChatResponse resp = api.completions(request);
// 内部执行的逻辑(简化版)
public Object invoke(Object proxy, Method method, Object[] args) {
// 1. 读取注解信息
POST annotation = method.getAnnotation(POST.class);
String path = annotation.value(); // "v1/chat/completions"
// 2. 处理参数
ChatRequest request = (ChatRequest) args[0];
// 3. 构造请求
Request okHttpRequest = new Request.Builder()
.url(baseUrl + path)
.post(serializeToJson(request))
.build();
// 4. 发送请求并解析
Response response = okHttpClient.newCall(okHttpRequest).execute();
return deserializeFromJson(response.body().string());
}
执行流程图:
chatApi.completions(request)
│
▼
┌───────────────────┐
│ Retrofit 代理 │ ← 拦截方法调用
└─────────┬─────────┘
│
▼
┌───────────────────┐
│ 读取接口注解 │ @POST、@Body 等
└─────────┬─────────┘
│
▼
┌───────────────────┐
│ 序列化请求对象 │ Jackson → JSON
└─────────┬─────────┘
│
▼
┌───────────────────┐
│ 发送 OkHttp 请求 │
└─────────┬─────────┘
│
▼
┌───────────────────┐
│ 反序列化响应 │ JSON → Java 对象
└─────────┬─────────┘
│
▼
返回结果
3.4 常用注解
| 注解 | 作用 | 示例 |
|---|---|---|
@GET |
GET 请求 | @GET("v1/models") |
@POST |
POST 请求 | @POST("v1/chat/completions") |
@PUT |
PUT 请求 | @PUT("v1/models/{id}") |
@DELETE |
DELETE 请求 | @DELETE("v1/models/{id}") |
@Body |
请求体 | @Body ChatRequest request |
@Path |
URL 路径参数 | @Path("id") String id |
@Query |
URL 查询参数 | @Query("limit") int limit |
@Header |
请求头 | @Header("Authorization") String auth |
@Headers |
静态请求头 | @Headers("Content-Type: application/json") |
@FormUrlEncoded |
表单编码 | |
@Multipart |
多部分请求 |
3.5 转换器(Converter)
Retrofit 需要转换器来处理 JSON 和 Java 对象之间的转换:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.openai.com/")
.addConverterFactory(JacksonConverterFactory.create()) // Jackson
// .addConverterFactory(GsonConverterFactory.create()) // Gson
// .addConverterFactory(MoshiConverterFactory.create()) // Moshi
.build();
3.6 调用适配器(Call Adapter)
调用适配器决定方法返回值的类型:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.openai.com/")
.addCallAdapterFactory(RxJava2CallAdapterFactory.create()) // RxJava
// .addCallAdapterFactory(CoroutineCallAdapterFactory.create()) // Kotlin Coroutine
.build();
// 使用 RxJava
public interface OpenAiApi {
@POST("v1/chat/completions")
Single<ChatResponse> completions(@Body ChatRequest request);
}
四、OkHttp 与 Retrofit 的配合
4.1 基本配置
// 1. 先配置 OkHttp
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.connectTimeout(30, TimeUnit.SECONDS)
.addInterceptor(new AuthInterceptor())
.addInterceptor(new HttpLoggingInterceptor())
.build();
// 2. 再配置 Retrofit
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.openai.com/")
.client(okHttpClient) // 使用 OkHttp
.addConverterFactory(JacksonConverterFactory.create()) // JSON 转换
.addCallAdapterFactory(RxJava2CallAdapterFactory.create()) // RxJava
.build();
// 3. 创建 API 实例
OpenAiApi api = retrofit.create(OpenAiApi.class);
4.2 在 SDK 中的应用
在 ChatGPT SDK 中的实际应用示例:
// DefaultOpenAiSessionFactory.java
@Override
public OpenAiSession openSession() {
// 1. 创建 OkHttpClient
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.addInterceptor(new HttpLoggingInterceptor())
.addInterceptor(new OpenAiInterceptor(apiKey, authToken))
.connectTimeout(450, TimeUnit.SECONDS)
.build();
// 2. 创建 Retrofit
IOpenAiApi openAiApi = new Retrofit.Builder()
.baseUrl(configuration.getApiHost())
.client(okHttpClient)
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(JacksonConverterFactory.create())
.build().create(IOpenAiApi.class);
// 3. 返回会话
return new DefaultOpenAiSession(configuration);
}
五、对比总结
5.1 核心差异
| 对比项 | OkHttp | Retrofit |
|---|---|---|
| 定位 | 底层 HTTP 客户端 | REST API 封装层 |
| 职责 | 处理实际网络通信 | 简化 API 调用 |
| 用法 | 命令式(手动构造请求) | 声明式(接口 + 注解) |
| 灵活性 | 高(底层控制) | 低(受限于注解) |
| 学习曲线 | 较简单 | 较陡峭(注解较多) |
| 适用场景 | 需要精细控制 HTTP 细节 | 标准 REST API 调用 |
5.2 二者关系图
┌─────────────────────────────────────────────────────────────┐
│ 架构层次 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 应用层 │
│ └── API 接口定义(Retrofit) │
│ │
│ 封装层 │
│ └── Retrofit(注解处理、序列化、动态代理) │
│ │
│ 传输层 │
│ └── OkHttp(连接池、拦截器、HTTP 协议) │
│ │
│ 网络层 │
│ └── TCP/IP │
│ │
└─────────────────────────────────────────────────────────────┘
5.3 使用建议
| 场景 | 推荐方案 |
|---|---|
| 简单的 HTTP 请求 | 直接使用 OkHttp |
| 复杂的 REST API | Retrofit + OkHttp |
| 需要流式响应(SSE) | OkHttp 原生支持 |
| 需要自定义认证逻辑 | OkHttp 拦截器 |
| 需要优雅的 API 设计 | Retrofit |
六、常见问题
6.1 为什么要用拦截器?
- 统一处理:认证、日志、重试等逻辑集中处理
- 解耦:业务代码与 HTTP 细节分离
- 可复用:拦截器可以在多个请求中复用
6.2 Retrofit 返回的 Call 是什么?
Call<T> 是 Retrofit 的请求封装类:
execute():同步执行enqueue(Callback):异步执行cancel():取消请求clone():克隆请求
6.3 如何处理错误?
try {
Response<ChatResponse> response = api.completions(request).execute();
if (response.isSuccessful()) {
ChatResponse body = response.body();
// 成功处理
} else {
String errorBody = response.errorBody().string();
// 错误处理
}
} catch (IOException e) {
// 网络错误
}
6.4 为什么需要转换器?
Retrofit 本身不处理 JSON 序列化,需要依赖转换器:
- Jackson
- Gson
- Moshi
七、总结
| 库 | 定位 | 核心价值 |
|---|---|---|
| OkHttp | 底层 HTTP 客户端 | 高性能、可扩展、支持流式响应 |
| Retrofit | REST API 封装层 | 声明式 API、自动序列化、代码整洁 |
最佳实践:
- 使用 Retrofit 定义 API 接口
- 使用 OkHttp 配置底层通信(超时、拦截器等)
- 使用 Jackson/Gson 处理 JSON 转换
- 使用 RxJava/Coroutine 处理异步
比喻:
- OkHttp = 快递员,负责高效地把包裹送到目的地
- Retrofit = 快递公司的 App,让你用最简洁的方式下单
- 转换器 = 包裹打包服务,自动把物品打包成标准格式
注意:retrofit不支持sse。
SSE 是什么?
- 流式响应,服务器一段一段推送数据
- 像看视频,边下边播
- 需要持续监听数据流
Retrofit 的定位:
- 标准的 Request/Response
- 一次请求,一次响应
- 不适合流式场景
OkHttp SSE:
- OkHttp 原生支持 SSE
- EventSource 可以持续监听
- 适合流式响应
流式请求的典型使用场景
- 提升用户体验 - 像官网一样逐字显示
当 AI 生成较长内容时(如写代码、写文章),流式请求可以让内容 逐字逐句地显示 ,而不是等全部生成完才一次性显示。 - 处理长响应内容
当 AI 回复内容很长时,流式请求可以:
- 避免等待时间过长导致用户焦虑
- 可以在收到部分内容时就开始处理
- 减少内存占用(不需要一次性加载完整响应)
- 实时交互场景
- 聊天机器人 :边生成边显示,模拟真人打字效果
- 代码助手 :生成代码时可以逐行显示
- 内容创作 :写文章、故事时实时预览
- 可中断的请求
流式请求可以随时取消(通过 EventSource.cancel() ),如果用户发现 AI 跑题了,可以立即停止。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)