使用okhttp3发送请求
一、OkHttp3 简介
OkHttp3 是一个高效的 HTTP 客户端,由 Square 公司开发,具有以下核心特点:
• 连接池 - 减少请求延迟,支持HTTP/2和SPDY
• 透明GZIP压缩 - 自动压缩请求体,减少数据传输量
• 响应缓存 - 避免重复网络请求
• 自动重试 - 处理瞬时故障和网络问题
• 异步/同步支持 - 灵活的调用方式
二、使用示例
准备工作
引入依赖:
<dependency><groupId>com.squareup.okhttp3</groupId><artifactId>okhttp</artifactId><version>4.12.0</version>
</dependency>
创建OkHttpClient实例
import okhttp3.*;import java.io.IOException;
import java.util.concurrent.TimeUnit;public class OkHttpExample {// 创建全局OkHttpClient实例private static final OkHttpClient client = new OkHttpClient.Builder().connectTimeout(10, TimeUnit.SECONDS).readTimeout(30, TimeUnit.SECONDS).writeTimeout(30, TimeUnit.SECONDS).addInterceptor(new LoggingInterceptor()) // 添加日志拦截器.build();// 简单的日志拦截器static class LoggingInterceptor implements Interceptor {@Overridepublic Response intercept(Chain chain) throws IOException {Request request = chain.request();long startTime = System.nanoTime();System.out.println(String.format("Sending request %s on %s%n%s",request.url(), chain.connection(), request.headers()));Response response = chain.proceed(request);long endTime = System.nanoTime();System.out.println(String.format("Received response for %s in %.1fms%n%s",response.request().url(), (endTime - startTime) / 1e6d, response.headers()));return response;}}
}
1.发送GET请求
下面的示例涵盖普通get请求,带查询参数的get请求和带请求头的get请求。
public class GetRequestExample {public static void basicGetRequest() throws IOException {String url = "https://jsonplaceholder.typicode.com/posts/1";Request request = new Request.Builder().url(url).get() // 显式声明GET方法,可选.build();try (Response response = client.newCall(request).execute()) {if (!response.isSuccessful()) {throw new IOException("Unexpected code: " + response);}String responseBody = response.body().string();System.out.println("Response: " + responseBody);}}// 带查询参数的GET请求public static void getWithQueryParams() throws IOException {HttpUrl url = HttpUrl.parse("https://jsonplaceholder.typicode.com/posts").newBuilder().addQueryParameter("userId", "1").addQueryParameter("_limit", "5").build();Request request = new Request.Builder().url(url).build();try (Response response = client.newCall(request).execute()) {System.out.println("Response: " + response.body().string());}}// 带请求头的GET请求public static void getWithHeaders() throws IOException {Request request = new Request.Builder().url("https://api.github.com/users/octocat").addHeader("User-Agent", "OkHttp-Example").addHeader("Accept", "application/vnd.github.v3+json").addHeader("Authorization", "Bearer your-token-here").build();try (Response response = client.newCall(request).execute()) {System.out.println("Response: " + response.body().string());}}
}
2. 发送POST请求
下面的示例涵盖,发送json数据,表单数据和文件上传的post请求
public class PostRequestExample {// POST JSON数据public static void postJson() throws IOException {String json = "{\"title\":\"foo\",\"body\":\"bar\",\"userId\":1}";RequestBody body = RequestBody.create(json,MediaType.parse("application/json; charset=utf-8"));Request request = new Request.Builder().url("https://jsonplaceholder.typicode.com/posts").post(body).addHeader("Content-Type", "application/json").build();try (Response response = client.newCall(request).execute()) {System.out.println("Response: " + response.body().string());}}// 发送表单数据public static void postForm() throws IOException {RequestBody formBody = new FormBody.Builder().add("username", "john_doe").add("password", "secret123").add("grant_type", "password").build();Request request = new Request.Builder().url("https://httpbin.org/post").post(formBody).build();try (Response response = client.newCall(request).execute()) {System.out.println("Response: " + response.body().string());}}// 发送multipart表单(文件上传)public static void postMultipart() throws IOException {RequestBody requestBody = new MultipartBody.Builder().setType(MultipartBody.FORM).addFormDataPart("title", "My File").addFormDataPart("file", "filename.txt",RequestBody.create("file content", MediaType.parse("text/plain"))).addFormDataPart("image", "image.jpg",RequestBody.create(new byte[]{/* 图片数据 */}, MediaType.parse("image/jpeg"))).build();Request request = new Request.Builder().url("https://httpbin.org/post").post(requestBody).build();try (Response response = client.newCall(request).execute()) {System.out.println("Response: " + response.body().string());}}
}
3.发送PUT请求
public static void putRequest() throws IOException {String json = "{\"id\":1,\"title\":\"updated title\",\"body\":\"updated body\",\"userId\":1}";RequestBody body = RequestBody.create(json,MediaType.parse("application/json; charset=utf-8"));Request request = new Request.Builder().url("https://jsonplaceholder.typicode.com/posts/1").put(body).build();try (Response response = client.newCall(request).execute()) {System.out.println("PUT Response: " + response.body().string());}}
4.发送PATCH请求
PATCH 请求用于对资源进行部分更新,与 PUT(全量更新)不同,PATCH 只更新提供的字段。
public static void patchRequest() throws IOException {String json = "{\"title\":\"patched title\"}";RequestBody body = RequestBody.create(json,MediaType.parse("application/json; charset=utf-8"));Request request = new Request.Builder().url("https://jsonplaceholder.typicode.com/posts/1").patch(body).build();try (Response response = client.newCall(request).execute()) {System.out.println("PATCH Response: " + response.body().string());}}
5.发送DELETE请求
public static void deleteRequest() throws IOException {Request request = new Request.Builder().url("https://jsonplaceholder.typicode.com/posts/1").delete().build();try (Response response = client.newCall(request).execute()) {System.out.println("DELETE Response: " + response.body().string());}}
6.发送异步请求
public class AsyncRequestExample {public static void asyncGetRequest() {Request request = new Request.Builder().url("https://jsonplaceholder.typicode.com/posts/1").build();client.newCall(request).enqueue(new Callback() {@Overridepublic void onFailure(Call call, IOException e) {e.printStackTrace();}@Overridepublic void onResponse(Call call, Response response) throws IOException {if (!response.isSuccessful()) {throw new IOException("Unexpected code: " + response);}String responseBody = response.body().string();System.out.println("Async Response: " + responseBody);// 注意:在异步回调中需要手动关闭response bodyresponse.close();}});System.out.println("Request sent asynchronously...");}// 多个异步请求并行执行public static void multipleAsyncRequests() {String[] urls = {"https://jsonplaceholder.typicode.com/posts/1","https://jsonplaceholder.typicode.com/posts/2","https://jsonplaceholder.typicode.com/posts/3"};for (String url : urls) {Request request = new Request.Builder().url(url).build();client.newCall(request).enqueue(new Callback() {@Overridepublic void onFailure(Call call, IOException e) {System.err.println("Request failed: " + e.getMessage());}@Overridepublic void onResponse(Call call, Response response) throws IOException {if (response.isSuccessful()) {System.out.println("Response from " + call.request().url() + ": " + response.body().string().substring(0, 50) + "...");}response.close();}});}}
}
7.高级功能和配置
涵盖:添加认证token、重试拦截器、下载文件和使用Cookie
public class AdvancedFeatures {// 自定义配置的Clientprivate static final OkHttpClient customClient = new OkHttpClient.Builder().connectTimeout(15, TimeUnit.SECONDS).readTimeout(30, TimeUnit.SECONDS).writeTimeout(30, TimeUnit.SECONDS).addInterceptor(chain -> {// 添加认证tokenRequest original = chain.request();Request authenticated = original.newBuilder().header("Authorization", "Bearer " + getAuthToken()).build();return chain.proceed(authenticated);}).addInterceptor(chain -> {// 重试拦截器int maxRetries = 3;int retryCount = 0;Response response = null;while (retryCount < maxRetries) {try {response = chain.proceed(chain.request());if (response.isSuccessful() || retryCount == maxRetries - 1) {break;}} catch (IOException e) {if (retryCount == maxRetries - 1) {throw e;}}retryCount++;System.out.println("Retrying request, attempt: " + (retryCount + 1));}return response;}).build();private static String getAuthToken() {return "your-auth-token";}// 下载文件public static void downloadFile() throws IOException {Request request = new Request.Builder().url("https://httpbin.org/image/jpeg").build();try (Response response = client.newCall(request).execute()) {if (response.isSuccessful()) {byte[] fileData = response.body().bytes();// 保存文件到本地// Files.write(Paths.get("image.jpg"), fileData);System.out.println("File downloaded, size: " + fileData.length + " bytes");}}}// 使用Cookiepublic static void withCookieJar() {CookieJar cookieJar = new CookieJar() {private final List<Cookie> cookies = new ArrayList<>();@Overridepublic void saveFromResponse(HttpUrl url, List<Cookie> cookies) {this.cookies.addAll(cookies);}@Overridepublic List<Cookie> loadForRequest(HttpUrl url) {return cookies;}};OkHttpClient clientWithCookies = new OkHttpClient.Builder().cookieJar(cookieJar).build();}
}
8.OkHttp工具类
简单Mini版的使用示例
public class OkHttpUtils {private static final OkHttpClient client = new OkHttpClient();public static String doGet(String url) throws IOException {Request request = new Request.Builder().url(url).build();try (Response response = client.newCall(request).execute()) {if (!response.isSuccessful()) {throw new IOException("Request failed: " + response);}return response.body().string();}}public static String doPost(String url, String json) throws IOException {RequestBody body = RequestBody.create(json, MediaType.parse("application/json; charset=utf-8"));Request request = new Request.Builder().url(url).post(body).build();try (Response response = client.newCall(request).execute()) {if (!response.isSuccessful()) {throw new IOException("Request failed: " + response);}return response.body().string();}}// 使用示例public static void main(String[] args) {try {// GET请求String getResponse = doGet("https://jsonplaceholder.typicode.com/posts/1");System.out.println("GET Response: " + getResponse);// POST请求String json = "{\"title\":\"test\",\"body\":\"content\",\"userId\":1}";String postResponse = doPost("https://jsonplaceholder.typicode.com/posts", json);System.out.println("POST Response: " + postResponse);} catch (IOException e) {e.printStackTrace();}}
}
三、适用场景
移动应用开发;
微服务间的HTTP通信;
- 文件上传下载;
需要精细控制HTTP请求的场景;
- Web爬虫和数据采集。
四、性能优势场景
高并发请求
// 连接池复用,适合高并发
for (int i = 0; i < 1000; i++) {Request request = new Request.Builder().url("http://api.example.com/items/" + i).build();client.newCall(request).enqueue(callback); // 连接复用
}
五、注意事项
同步请求:使用
execute()
方法,会阻塞当前线程异步请求:使用
enqueue()
方法,不会阻塞当前线程请求构建:使用
Request.Builder
构建请求响应处理:注意需要手动关闭Response body
连接池:OkHttp自动管理连接池,提高性能
拦截器:可以添加各种拦截器实现日志、认证、重试等功能
六、与其他HTTP客户端对比
场景 | 推荐工具 | 理由 |
---|---|---|
Android应用 | OkHttp3 | 官方推荐,性能优化 |
Spring Boot微服务 | OpenFeign | 声明式,集成性好 |
简单Java应用 | OkHttp3 | 轻量,易用 |
高并发爬虫 | OkHttp3 | 连接池,异步支持 |
需要精细控制 | OkHttp3 | 拦截器,自定义配置 |