Java中使用OKHTTP3的详细教程与实战应用案例

 更新时间:2026年01月20日 10:40:19   作者:就这个丶调调  
okhttp是当下主流的网络请求的开源框架,效率很高,使用起来也非常方便,这篇文章主要介绍了Java中使用OKHTTP3的详细教程与实战应用案例的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下

引言:为什么选择okhttp?

在现代Java开发中,进行网络请求是几乎每个项目都不可避免的需求。虽然JDK自带的java.net.HttpURLConnection可以完成基本任务,但它在代码复杂度、功能丰富性和易用性上存在明显短板。这时,okhttp便成为了开发者们的首选。

OKHTTP3是由Square公司开源的一个高性能、易于使用的HTTP客户端库,它不仅提供了简洁的API,还内置了诸多高级特性,如连接池、缓存、拦截器、异步请求等。本教程将带你从零开始,深入掌握okhttp的核心概念与各种应用场景,无论是简单的GET/POST请求,还是复杂的文件上传下载、自定义拦截器、超时控制等,你都能在这里找到清晰的解决方案。

一、环境准备与基础配置

1.1 添加依赖(Maven)

在你的pom.xml文件中添加以下依赖:

<dependency>
    <groupId>com.squareup.okhttp3</groupId>
    <artifactId>okhttp</artifactId>
    <version>4.12.0</version>
</dependency>

注意:请根据你的项目需求和兼容性,选择合适的版本。建议使用最新的稳定版本以获得最佳性能和安全性。

1.2 基础类:OkHttpClient

OkHttpClient是所有HTTP请求的发起者,它是线程安全的,并且可以被多个请求共享。通常,我们只创建一个全局的OkHttpClient实例,以利用其内部的连接池和缓存机制,从而提高性能。

import okhttp3.OkHttpClient;

public class OkHttpConfig {
    // 全局唯一的OkHttpClient实例
    private static final OkHttpClient client = new OkHttpClient();

    public static OkHttpClient getClient() {
        return client;
    }
}

二、核心操作:GET与POST请求

2.1 GET请求:获取数据

GET请求是最常见的请求类型,用于从服务器获取资源。

简单示例:

import okhttp3.*;

public class GetExample {
    public static void main(String[] args) throws Exception {
        // 1. 创建一个Request对象,指定URL
        Request request = new Request.Builder()
                .url("https://jsonplaceholder.typicode.com/posts/1")
                .build();

        // 2. 使用OkHttpClient执行请求,获取Response
        try (Response response = OkHttpConfig.getClient().newCall(request).execute()) {
            if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);

            // 3. 读取响应体中的文本内容
            String responseBody = response.body().string();
            System.out.println("Response: " + responseBody);
        }
    }
}

解释:

  • Request.Builder():构建请求的起始点。
  • .url():设置目标URL。
  • .build():构建最终的Request对象。
  • newCall(request).execute():创建一个调用并同步执行,返回Response
  • response.body().string():将响应体转换为字符串,这是最常用的读取方式之一。

2.2 POST请求:提交数据

POST请求用于向服务器提交数据,常用于表单提交、创建资源等场景。

2.2.1 表单数据(application/x-www-form-urlencoded)

import okhttp3.FormBody;
import okhttp3.RequestBody;

public class PostFormExample {
    public static void main(String[] args) throws Exception {
        // 1. 构建表单数据体
        RequestBody formBody = new FormBody.Builder()
                .add("username", "john_doe")
                .add("email", "john@example.com")
                .build();

        // 2. 创建POST请求,将表单数据体附加到请求中
        Request request = new Request.Builder()
                .url("https://httpbin.org/post")
                .post(formBody)
                .build();

        // 3. 执行请求
        try (Response response = OkHttpConfig.getClient().newCall(request).execute()) {
            if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);

            String responseBody = response.body().string();
            System.out.println("Response: " + responseBody);
        }
    }
}

2.2.2 JSON数据(application/json)

import okhttp3.MediaType;
import okhttp3.RequestBody;

public class PostJsonExample {
    public static void main(String[] args) throws Exception {
        // 1. 定义JSON媒体类型
        MediaType JSON = MediaType.get("application/json; charset=utf-8");

        // 2. 构建JSON字符串作为请求体
        String json = "{\"name\": \"Alice\", \"age\": 30}";

        // 3. 创建RequestBody
        RequestBody body = RequestBody.create(json, JSON);

        // 4. 创建POST请求,附带请求体
        Request request = new Request.Builder()
                .url("https://httpbin.org/post")
                .post(body)
                .build();

        // 5. 执行请求
        try (Response response = OkHttpConfig.getClient().newCall(request).execute()) {
            if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);

            String responseBody = response.body().string();
            System.out.println("Response: " + responseBody);
        }
    }
}

2.2.3 上传文件(multipart/form-data)

import okhttp3.MultipartBody;

public class UploadFileExample {
    public static void main(String[] args) throws Exception {
        // 1. 创建MultipartBody.Builder来构建多部分表单
        MultipartBody.Builder multipartBuilder = new MultipartBody.Builder()
                .setType(MultipartBody.FORM); // 指定为form-data

        // 2. 添加文件部分:需要提供文件路径和文件名(可选)
        File file = new File("path/to/your/file.txt");
        multipartBuilder.addFormDataPart("file", file.getName(), 
                RequestBody.create(MediaType.parse("text/plain"), file));

        // 3. 添加其他表单字段(可选)
        multipartBuilder.addFormDataPart("description", "This is a test file.");

        // 4. 构建完整的RequestBody
        RequestBody requestBody = multipartBuilder.build();

        // 5. 创建POST请求,使用multipart/form-data
        Request request = new Request.Builder()
                .url("https://httpbin.org/post")
                .post(requestBody)
                .build();

        // 6. 执行请求
        try (Response response = OkHttpConfig.getClient().newCall(request).execute()) {
            if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);

            String responseBody = response.body().string();
            System.out.println("Response: " + responseBody);
        }
    }
}

三、进阶技巧:异步请求与回调

3.1 同步 vs 异步请求

  • 同步请求:调用execute()会阻塞当前线程,直到请求完成。适合在简单脚本或非主线程中使用。
  • 异步请求:调用enqueue(),将请求放入队列,由后台线程处理。不会阻塞主线程,是UI应用和高并发服务的首选。

3.2 异步请求示例(Callback)

import okhttp3.Callback;
import okhttp3.Response;

public class AsyncRequestExample {
    public static void main(String[] args) {
        Request request = new Request.Builder()
                .url("https://jsonplaceholder.typicode.com/posts/1")
                .build();

        // 1. 使用enqueue方法发送异步请求,传入Callback
        OkHttpConfig.getClient().newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                // 请求失败时的回调,例如网络错误、超时等
                System.err.println("Request failed: " + e.getMessage());
                e.printStackTrace();
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                // 请求成功时的回调,此时response已经可用
                if (!response.isSuccessful()) {
                    System.err.println("Unexpected code " + response);
                    return;
                }

                // 读取响应体内容
                String responseBody = response.body().string();
                System.out.println("Async Response: " + responseBody);

                // 重要:必须关闭response.body(),否则可能造成资源泄漏!
                // 因为这里是在回调里,所以不能用try-with-resources,需要手动关闭。
                // 但请注意,在实际项目中,应确保此逻辑的健壮性。
                response.close();
            }
        });

        // 2. 注意:主线程不会等待异步请求完成,会立即继续执行后续代码。
        // 这里为了演示,可以加一个sleep,让程序运行一段时间。
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

四、高级功能:拦截器(Interceptors)

4.1 什么是拦截器?

拦截器是OKHTTP3中一个极其强大的特性。它允许你在请求发出前或响应返回后,对请求或响应进行修改、记录日志、添加认证头等操作。它的工作原理类似于一个“中间件”或“过滤器”。

4.2 应用场景:日志记录与调试

import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;

public class LoggingInterceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        // 1. 获取原始请求
        Request request = chain.request();

        // 2. 记录请求信息(时间、方法、URL、Headers)
        long startTime = System.currentTimeMillis();
        System.out.println("Sending request to: " + request.url());
        System.out.println("Method: " + request.method());
        System.out.println("Headers: " + request.headers());

        // 3. 继续执行请求(关键步骤)
        Response response = chain.proceed(request);

        // 4. 记录响应信息(状态码、耗时、响应体大小)
        long endTime = System.currentTimeMillis();
        System.out.println("Received response in " + (endTime - startTime) + "ms");
        System.out.println("Status Code: " + response.code());
        System.out.println("Response Body Size: " + response.body().contentLength() + " bytes");

        // 5. 返回修改后的响应(通常不需要修改,直接返回原响应)
        return response;
    }
}

4.3 将拦截器应用到客户端

// 1. 为OkHttpClient添加拦截器(注意:拦截器分为两种:Application Interceptor & Network Interceptor)
// 这里我们使用Application Interceptor,它会在请求发出前和响应返回后各执行一次。
OkHttpClient client = new OkHttpClient.Builder()
        .addInterceptor(new LoggingInterceptor())
        .build();

// 2. 使用这个带有拦截器的client进行请求,日志就会自动打印出来。

4.4 应用场景:添加认证头(Token)

import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;

public class AuthInterceptor implements Interceptor {
    private final String token;

    public AuthInterceptor(String token) {
        this.token = token;
    }

    @Override
    public Response intercept(Chain chain) throws IOException {
        // 1. 获取原始请求
        Request originalRequest = chain.request();

        // 2. 创建一个新的请求,添加Authorization Header
        Request authenticatedRequest = originalRequest.newBuilder()
                .header("Authorization", "Bearer " + token)
                .build();

        // 3. 继续执行带有认证头的请求
        return chain.proceed(authenticatedRequest);
    }
}
// 应用该拦截器,确保所有请求都携带Token
OkHttpClient client = new OkHttpClient.Builder()
        .addInterceptor(new AuthInterceptor("your-jwt-token-here"))
        .build();

五、综合案例:一个完整的用户登录与信息查询应用

下面是一个整合了多种技术的完整示例,模拟一个用户登录后查询个人信息的流程。

import okhttp3.*;
import java.io.IOException;
import java.util.concurrent.TimeUnit;

public class UserLoginApp {
    private static final OkHttpClient client = new OkHttpClient.Builder()
            .connectTimeout(10, TimeUnit.SECONDS) // 连接超时10秒
            .readTimeout(30, TimeUnit.SECONDS)   // 读取超时30秒
            .writeTimeout(30, TimeUnit.SECONDS)  // 写入超时30秒
            .addInterceptor(new LoggingInterceptor())
            .addInterceptor(new AuthInterceptor("initial-token"))
            .build();

    public static void main(String[] args) {
        // 1. 用户登录,获取token
        String loginToken = loginUser("admin", "password123");

        if (loginToken == null) {
            System.err.println("Login failed!");
            return;
        }

        // 2. 使用获取到的token,查询用户信息(此时AuthInterceptor会自动添加token)
        getUserInfo(loginToken);
    }

    private static String loginUser(String username, String password) {
        RequestBody formBody = new FormBody.Builder()
                .add("username", username)
                .add("password", password)
                .build();

        Request request = new Request.Builder()
                .url("https://api.example.com/login")
                .post(formBody)
                .build();

        try (Response response = client.newCall(request).execute()) {
            if (!response.isSuccessful()) {
                System.err.println("Login failed: " + response.code());
                return null;
            }

            // 假设响应体包含一个名为"token"的JSON字段,这里简化处理,仅返回字符串形式的token
            // 实际项目中应使用JSON解析库(如Jackson)来解析响应体。
            String responseBody = response.body().string();
            System.out.println("Login success, token: " + responseBody);
            return responseBody;
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    private static void getUserInfo(String token) {
        // 由于我们已经在client中添加了AuthInterceptor,所以这里无需再手动添加token
        Request request = new Request.Builder()
                .url("https://api.example.com/user/profile")
                .get() // GET请求获取信息
                .build();

        // 使用异步请求,避免阻塞主线程
        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                System.err.println("Failed to fetch user info: " + e.getMessage());
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                if (!response.isSuccessful()) {
                    System.err.println("Unexpected code: " + response.code());
                    return;
                }

                String responseBody = response.body().string();
                System.out.println("User Info: " + responseBody);
                response.close();
            }
        });

        // 主线程继续执行,不等待异步请求完成。
        System.out.println("Fetching user info... (async)");
    }
}

总结:如何选择与使用?

场景推荐方案
简单的同步请求newCall(request).execute()
需要保持主线程响应性的场景(如Android UI)newCall(request).enqueue(callback)
需要统一管理日志、认证、重试等使用OkHttpClient.Builder添加Interceptor
需要自定义超时策略OkHttpClient.Builder中设置connectTimeout, readTimeout, writeTimeout
需要上传大文件结合MultipartBody和异步请求,考虑分块上传或进度回调

OKHTTP3的强大之处在于它的灵活性和可扩展性。通过合理地组合这些组件,你可以构建出健壮、高效、易于维护的网络层。希望这篇详尽的教程能成为你学习和使用OKHTTP3的坚实基石!

最后提醒:始终记得在使用Response.body()后调用close()方法,以释放底层的网络资源,防止内存泄漏。在异步回调中,这一点尤为重要。

到此这篇关于Java中使用OKHTTP3的详细教程与实战应用案例的文章就介绍到这了,更多相关Java使用OKHTTP3内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 面试必问项之Set实现类:TreeSet

    面试必问项之Set实现类:TreeSet

    这篇文章主要介绍了Java TreeSet类的简单理解和使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2021-07-07
  • Java ArrayList类的基础使用讲解

    Java ArrayList类的基础使用讲解

    数组的长度是固定的,无法适应数据变化的需求。为了解决这个问题,Java提供了另一个容器 java.util.ArrayList集合类,让我们可以更便捷的存储和操作对象数据。本文就将通过示例聊聊ArrayList类的基础使用,感兴趣的可以了解一下
    2022-10-10
  • 一文带你搞懂Java中的递归

    一文带你搞懂Java中的递归

    这篇文章主要为大家详细介绍了Java中的递归的实现以及应用,文中的示例代码讲解详细,对我们学习Java有一定帮助,需要的可以参考一下
    2022-10-10
  • Java 中 synchronized 的使用方式和锁升级

    Java 中 synchronized 的使用方式和锁升级

    Java中的synchronized关键字用于实现线程同步,保证同一时刻只有一个线程可以访问被同步的代码块或方法,JVM引入了锁升级机制,从无锁状态开始,根据竞争情况逐步升级为偏向锁、轻量级锁和重量级锁,以提高性能,感兴趣的朋友一起看看吧
    2025-03-03
  • Mybatis-Plus中and()和or()的使用与原理详解

    Mybatis-Plus中and()和or()的使用与原理详解

    最近发现MyBatisPlus还是挺好用的,下面这篇文章主要给大家介绍了关于Mybatis-Plus中and()和or()的使用与原理的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-09-09
  • 详解Java中final的用法

    详解Java中final的用法

    本文主要介绍了Java中final的使用方法,final是java的关键字,本文就详细说明一下它的使用方法,需要的朋友可以参考下
    2015-08-08
  • Apache Camel的Java编程入门指南

    Apache Camel的Java编程入门指南

    这篇文章主要介绍了Apache Camel的Java编程入门指南,Apache Camel规则路由引擎中提供了很多Java可扩展接口,需要的朋友可以参考下
    2015-07-07
  • 源码解析springbatch的job运行机制

    源码解析springbatch的job运行机制

    这篇文章主要介绍了springbatch的job是如何运行的,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-08-08
  • 关于@Autowired注解和静态方法及new的关系

    关于@Autowired注解和静态方法及new的关系

    这篇文章主要介绍了关于@Autowired注解和静态方法及new的关系,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-02-02
  • SpringBoot使用JSONPath实现高效处理JSON数据

    SpringBoot使用JSONPath实现高效处理JSON数据

    在日常开发中,我们经常需要处理 JSON 数据,特别是从复杂的 JSON 结构中提取特定字段,下面我们就来看看如何使用SpringBoot和JSONPath实现处理JSON数据吧
    2026-01-01

最新评论