OkHttp请求构建:Request、Response、Call的创建与执行流程

聊聊三个核心类

开始之前,我想先帮你理清三个最基础的东西:Request、Response 和 Call。说白了,Request 就是你想表达的请求意图——URL、Header、Body;Response 是服务器给你的回话——状态码、头、实体;而 Call 是连接这两个的“调度员”。

我在项目中遇到很多同事把 Request 和 Call 搞混。嗯,其实记一句就好:你构造 Request,然后用 OkHttpClient 的 newCall 创建 Call,最后由 Call 去执行并返回 Response。就这么简单。

Request 构建:Builder 模式怎么用

OkHttp 的 Request 用了 Builder 模式。我个人习惯这样写:

Request request = new Request.Builder()
    .url("https://api.example.com/users")
    .header("Authorization", "Bearer token123")
    .get()
    .build();

你想发 POST 就换成 .post(RequestBody)。注意 Builder 可以链式调用,每个方法回到自身,最后 build() 生成不可变对象。

小技巧:Header 是大小写敏感的,但 OkHttp 内部会帮你做规范化处理。我建议手动统一用小写,避免调试时困惑。

Call 是什么?你与服务器的“电话线”

Call 代表一次即将执行(或正在执行)的 HTTP 请求。它可以通过 OkHttpClient.newCall(request) 生成。记住,一个 Call 只能被执行一次,重复执行会抛异常。

Call 有两个执行方式:

  • 同步:call.execute(),直接返回 Response,会阻塞当前线程。
  • 异步:call.enqueue(Callback),在内部线程池里跑,回调通知结果。

我曾经写过一段代码,在 Android 主线程里调了 execute(),结果直接 ANR。嗯,网络请求永远不要跑在主线程,除非你明确知道自已在干嘛。

Response:数据拿到了,然后呢?

Response 对象包含:

属性说明典型值
code()HTTP 状态码200, 404, 500
message()状态消息"OK", "Not Found"
headers()所有响应头Content-Type, Date…
body()响应体只能消费一次
注意!Response 的 body() 是流式的,只能读一次。如果你忘了关闭 Response,句柄会泄漏。我曾在线上排查过一个 OOM 问题,最后发现就是 Response 没 close。

完整的执行流程

为了让你一眼看明白整个链条,我画了一张流程图。看看它怎么从构造到结束:

OkHttp 请求构建与执行流程 OkHttpClient Request.Builder Request (不可变) Call (一次性的) execute() → 阻塞返回 Response enqueue(Callback) → 回调 Response (流式,需关闭) ⚠️ 响应体用完必须 close(),否则泄漏 建议用 try/finally 或 use 扩展函数

实战中容易踩的坑

讲几个我亲自踩过的,给你当避坑指南:

  • Cache 过期没用:OkHttp 默认没开缓存。我建议如果你做列表请求,加一个 new OkHttpClient.Builder().cache(cache),能省不少流量。
  • Interceptor 误顺序:Application Interceptor 和 Network Interceptor 执行时机不同。我犯过在 Application 层加重试,结果死循环。
  • 忘记关闭 Response:这个最要命。现在 Kotlin 里可以用 response.use { … } 自动关闭,Java 就老老实实 try-finally。

一个小练习

你可以在自己的项目里试一下:构造一个 GET 请求,用同步方式获取豆瓣 API 的返回。然后打印出 Response 的 code、header 和 body 的前 200 个字符。注意处理好关闭哦。

OkHttpClient client = new OkHttpClient.Builder().build();
Request request = new Request.Builder()
    .url("https://api.douban.com/v2/book/1220562")
    .build();
Call call = client.newCall(request);
Response response = null;
try {
    response = call.execute();
    System.out.println("Response code: " + response.code());
    System.out.println("Header: " + response.header("Content-Type"));
    System.out.println("Body: " + response.body().string().substring(0, 200));
} finally {
    if (response != null) response.close();
}

嗯,跑通了的话,你就已经掌握了 OkHttp 最基本的请求构建和执行流程。接下来就是更深度的拦截器、连接池这些话题了——不过那是另一章的事。