OkHttp 发起 HTTP 请求:POST JSON、表单、文件上传与异步调用

Maven 依赖

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

GET 请求

OkHttpClient client = new OkHttpClient();

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

try (Response response = client.newCall(request).execute()) {
    String body = response.body().string();
    System.out.println(body);
}

POST JSON

OkHttpClient client = new OkHttpClient();

MediaType JSON = MediaType.get("application/json; charset=utf-8");
String json = "{\"username\": \"admin\", \"password\": \"secret\"}";

RequestBody body = RequestBody.create(json, JSON);

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

try (Response response = client.newCall(request).execute()) {
    System.out.println(response.body().string());
}

自定义 Header

Request request = new Request.Builder()
    .url("https://api.example.com/data")
    .header("Authorization", "Bearer your-token")
    .header("Content-Type", "application/json")
    .post(body)
    .build();

表单提交(application/x-www-form-urlencoded)

RequestBody formBody = new FormBody.Builder()
    .add("username", "admin")
    .add("password", "secret")
    .build();

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

文件上传(multipart/form-data)

File file = new File("/path/to/file.jpg");

RequestBody fileBody = RequestBody.create(file, MediaType.get("image/jpeg"));

RequestBody multipart = new MultipartBody.Builder()
    .setType(MultipartBody.FORM)
    .addFormDataPart("file", file.getName(), fileBody)
    .addFormDataPart("description", "头像上传")
    .build();

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

超时配置

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

异步请求(enqueue)

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 {
        try (ResponseBody body = response.body()) {
            System.out.println(body.string());
        }
    }
});

异步回调在 OkHttp 内部线程池中执行,Android 中更新 UI 需要切回主线程。

封装工具类

public class HttpUtil {

    private static final OkHttpClient CLIENT = new OkHttpClient.Builder()
        .connectTimeout(5, TimeUnit.SECONDS)
        .readTimeout(10, TimeUnit.SECONDS)
        .build();

    private static final MediaType JSON = MediaType.get("application/json; charset=utf-8");

    public static String get(String url) throws IOException {
        Request request = new Request.Builder().url(url).build();
        try (Response response = CLIENT.newCall(request).execute()) {
            return response.body().string();
        }
    }

    public static String postJson(String url, String json) throws IOException {
        RequestBody body = RequestBody.create(json, JSON);
        Request request = new Request.Builder().url(url).post(body).build();
        try (Response response = CLIENT.newCall(request).execute()) {
            return response.body().string();
        }
    }
}

OkHttpClient 实例应该全局复用,避免每次请求创建新实例浪费连接池资源。