1. OkHttp 简介与基本用法

说实话,最早我在做 Android 网络请求时,用的还是 HttpClient 那套老古董。后来换了 OkHttp,感觉世界都清净了。OkHttp 是什么?它就是 Google 官方钦定、 Android 平台上性能最好的 HTTP 客户端库。很多项目里的 Retrofit,底层其实也是它。我自己的习惯是,但凡涉及网络请求,直接上 OkHttp,省心。

1.1 OkHttp 的作用

OkHttp 能帮你做三件事:

  • 发起 HTTP/1.1 和 HTTP/2 请求 —— 支持同步和异步。
  • 自动管理连接池和复用 —— 减少握手开销,提升速度。
  • 支持拦截器链 —— 你可以在请求前后做日志、重试、缓存等操作。

另外,它还内置了 Gzip 解压、失败重试、Cookie 管理等能力。说白了,一个 OkHttpClient 对象,就能搞定 90% 的网络需求。

1.2 核心组件一览

OkHttp 的几个关键角色,我整理成了一张表,方便你对照理解:

组件 职责 备注
OkHttpClient 客户端核心对象,管理连接池、配置、拦截器 一般全局单例
Request 封装 URL、方法、头部、请求体 通过 Builder 构建
Call 代表一次准备执行的请求,可同步或异步 由 OkHttpClient 创建
Response 服务器返回的结果,包含状态码、头部、响应体 注意要关闭 body
Interceptor 拦截器,可插拔地处理请求/响应 分为应用层和网络层
Cache 缓存策略,配合 Cache-Control 头实现 需配置 Cache 目录

我记得刚开始用 OkHttp 时,老把 Call 和 Request 搞混。你只需记住:Request 是“我要什么”,Call 是“我去拿”。

1.3 基本请求/响应流程

下面这张图展示了 OkHttp 内部的工作流程,从创建客户端到获得响应。我在项目里排查网络问题时,经常对着这个流程来定位是哪个环节出了错。

OkHttp 请求/响应核心流程 OkHttpClient Request 应用拦截器链 Call 网络拦截器链 缓存策略 Response 说明:请求先经过应用拦截器,再经网络拦截器,最后通过缓存策略返回 Response

1.4 基本用法 —— 同步与异步请求

上手 OkHttp 最快的方式就是直接写代码。我一直觉得,看十遍文档不如自己跑一次请求。

小提示: OkHttpClient 建议做成单例,否则频繁创建会浪费连接池。我在老项目中就吃过这个亏。

同步请求

同步请求会阻塞当前线程,不能在主线程执行(Android 上会抛 NetworkOnMainThreadException)。

OkHttpClient client = new OkHttpClient.Builder()
        .connectTimeout(10, TimeUnit.SECONDS)
        .build();

Request request = new Request.Builder()
        .url("https://api.github.com/repos/square/okhttp")
        .get()
        .build();

try {
    Response response = client.newCall(request).execute();
    if (response.isSuccessful()) {
        String body = response.body().string();
        System.out.println("响应: " + body);
    }
    // 记得关闭 response.body()
    response.close();
} catch (IOException e) {
    e.printStackTrace();
}

异步请求

真实项目中我基本都用异步。不需要自己开线程,回调会在 OkHttp 的工作线程中执行。

OkHttpClient client = new OkHttpClient();

Request request = new Request.Builder()
        .url("https://api.github.com/")
        .build();

client.newCall(request).enqueue(new Callback() {
    @Override
    public void onFailure(Call call, IOException e) {
        e.printStackTrace();
    }

    @Override
    public void onResponse(Call call, Response response) throws IOException {
        if (response.isSuccessful()) {
            String body = response.body().string();
            System.out.println("异步结果: " + body);
        }
        response.close();
    }
});
警告: response.body().string() 只能调用一次!一次读取后流就关闭了。如果你需要多次使用响应体,最好先把内容缓存到字符串或 byte 数组中。

1.5 个人经验与避坑

我曾经在一个线上项目中,因为忘记在 finally 块里关闭 Response,导致连接泄漏,OOM 差点上线。从那以后,我养成习惯:要么用 try-with-resources,要么在回调里立马 close。

另外,OkHttp 默认是支持失败重试的(最多一次)。但如果你用的是异步,重试可能会导致回调被调用多次,这时要小心 UI 更新。我的做法是:在 onResponse 里加一个原子布尔锁,防止重复处理。

总结一下本章关键点:
  • OkHttp 是高性能 HTTP 客户端,核心为 OkHttpClient、Request、Call、Response。
  • 请求经过应用拦截器 → 网络拦截器 → 缓存策略 → 返回响应。
  • 同步用 execute(),异步用 enqueue()。
  • 记得关闭 Response,最好用 try-finally 或 try-with-resources。