跳到主要内容Java 中使用 OkHttp3 的网络请求教程与实战 | 极客日志Javajava
Java 中使用 OkHttp3 的网络请求教程与实战
OkHttp3 是 Square 公司开源的高性能 HTTP 客户端库。本文介绍在 Java 项目中集成 OkHttp3 的方法,包括 Maven 依赖配置、全局 OkHttpClient 实例管理。内容涵盖同步与异步请求实现、GET 与 POST(表单、JSON、文件上传)操作、拦截器(日志记录、Token 认证)的高级用法,以及超时控制等综合案例。通过实际代码示例,帮助开发者掌握网络请求的最佳实践,构建健壮高效的应用层。
Java 中使用 OkHttp3 的全面教程与实战应用
引言:为什么选择 OkHttp?
在现代 Java 开发中,进行网络请求是几乎每个项目都不可避免的需求。虽然 JDK 自带的 java.net.HttpURLConnection 可以完成基本任务,但它在代码复杂度、功能丰富性和易用性上存在明显短板。这时,OkHttp 便成为了开发者们的首选。
OkHttp3 是由 Square 公司开源的一个高性能、易于使用的 HTTP 客户端库,它不仅提供了简洁的 API,还内置了诸多高级特性,如连接池、缓存、拦截器、异步请求等。本教程将带你从零开始,深入掌握 OkHttp 的核心概念与各种应用场景,无论是简单的 GET/POST 请求,还是复杂的文件上传下载、自定义拦截器、超时控制等,你都能在这里找到清晰的解决方案。
一、环境准备与基础配置
1.1 添加依赖(Maven)
<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 {
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 {
Request request = new Request.Builder()
.url("https://jsonplaceholder.typicode.com/posts/1")
.build();
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);
}
}
}
解释:
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 {
RequestBody formBody = new FormBody.Builder()
.add("username", "john_doe")
.add("email", "[email protected]")
.build();
Request request = new Request.Builder()
.url("https://httpbin.org/post")
.post(formBody)
.build();
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 {
MediaType JSON = MediaType.get("application/json; charset=utf-8");
String json = "{\"name\": \"Alice\", \"age\": 30}";
RequestBody body = RequestBody.create(json, JSON);
Request request = new Request.Builder()
.url("https://httpbin.org/post")
.post(body)
.build();
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;
import java.io.File;
public class UploadFileExample {
public static void main(String[] args) throws Exception {
MultipartBody.Builder multipartBuilder = new MultipartBody.Builder()
.setType(MultipartBody.FORM);
File file = new File("path/to/your/file.txt");
multipartBuilder.addFormDataPart("file", file.getName(),
RequestBody.create(MediaType.parse("text/plain"), file));
multipartBuilder.addFormDataPart("description", "This is a test file.");
RequestBody requestBody = multipartBuilder.build();
Request request = new Request.Builder()
.url("https://httpbin.org/post")
.post(requestBody)
.build();
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();
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 {
if (!response.isSuccessful()) {
System.err.println("Unexpected code " + response);
return;
}
String responseBody = response.body().string();
System.out.println("Async Response: " + responseBody);
response.close();
}
});
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 {
Request request = chain.request();
long startTime = System.currentTimeMillis();
System.out.println("Sending request to: " + request.url());
System.out.println("Method: " + request.method());
System.out.println("Headers: " + request.headers());
Response response = chain.proceed(request);
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");
return response;
}
}
4.3 将拦截器应用到客户端
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(new LoggingInterceptor())
.build();
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 {
Request originalRequest = chain.request();
Request authenticatedRequest = originalRequest.newBuilder()
.header("Authorization", "Bearer " + token)
.build();
return chain.proceed(authenticatedRequest);
}
}
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)
.readTimeout(30, TimeUnit.SECONDS)
.writeTimeout(30, TimeUnit.SECONDS)
.addInterceptor(new LoggingInterceptor())
.addInterceptor(new AuthInterceptor("initial-token"))
.build();
public static void main(String[] args) {
String loginToken = loginUser("admin", "password123");
if (loginToken == null) {
System.err.println("Login failed!");
return;
}
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;
}
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) {
Request request = new Request.Builder()
.url("https://api.example.com/user/profile")
.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() 方法,以释放底层的网络资源,防止内存泄漏。在异步回调中,这一点尤为重要。
微信扫一扫,关注极客日志
微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
相关免费在线工具
- Keycode 信息
查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
- Escape 与 Native 编解码
JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
- JavaScript / HTML 格式化
使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
- JavaScript 压缩与混淆
Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
- Base64 字符串编码/解码
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
- Base64 文件转换器
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online