OkHttp入门

OkHttp 简介与使用示例

OkHttp 是一个高效的 HTTP 客户端,用于 Android、Java 应用程序以及 Kotlin 应用程序。它支持同步阻塞调用和异步调用,同时提供了强大的拦截器和重定向处理功能。OkHttp 由 Square 公司开发,因其高性能和易用性而广受欢迎。

为什么选择 OkHttp?

  • 性能:OkHttp 经过精心设计,以最小化网络延迟和数据使用量。
  • 简洁性:OkHttp 的 API 设计简洁直观,易于上手。
  • 可扩展性:OkHttp 支持自定义配置和拦截器,可以灵活地适应不同的需求。
  • 兼容性:OkHttp 支持 HTTP/2 和 WebSocket,适用于现代网络通信。

快速开始

首先,您需要在项目的 pom.xml 文件中添加 OkHttp 的依赖:

xml 复制代码
            <dependency>
                <groupId>com.squareup.okhttp3</groupId>
                <artifactId>okhttp</artifactId>
                <version>4.12.0</version>
            </dependency>

同步 GET 请求

以下是一个简单的同步 GET 请求示例:

java 复制代码
OkHttpClient client = new OkHttpClient();
String url = "https://api.example.com/data";

Request request = new Request.Builder()
        .url(url)
        .build();

try (Response response = client.newCall(request).execute()) {
    if (response.isSuccessful()) {
        String responseData = response.body().string();
        // 处理响应数据
    } else {
        // 处理错误响应
    }
} catch (IOException e) {
    // 处理网络异常
}

异步 GET 请求

对于不需要立即返回结果的场景,可以使用异步请求:

java 复制代码
client.newCall(request).enqueue(new Callback() {
    @Override
    public void onFailure(Call call, IOException e) {
        // 网络请求失败
    }

    @Override
    public void onResponse(Call call, Response response) throws IOException {
        if (response.isSuccessful()) {
            String responseData = response.body().string();
            // 异步处理响应数据
        } else {
            // 异步处理错误响应
        }
    }
});

POST 请求

发送 POST 请求并附带请求体:

java 复制代码
String url = "https://api.example.com/submit";
String json = "{\"name\":\"John\",\"age\":30}";

RequestBody body = RequestBody.create(json, MediaType.get("application/json; charset=utf-8"));
Request request = new Request.Builder()
        .url(url)
        .post(body)
        .build();

client.newCall(request).enqueue(new Callback() {
    @Override
    public void onFailure(Call call, IOException e) {
        // 网络请求失败
    }

    @Override
    public void onResponse(Call call, Response response) throws IOException {
        if (response.isSuccessful()) {
            // 请求成功
        } else {
            // 处理错误响应
        }
    }
});

上传文件

OkHttp 也支持文件上传:

java 复制代码
String url = "https://api.example.com/upload";
File file = new File("/sdcard/image.png");

RequestBody fileBody = RequestBody.create(MediaType.parse("image/png"), file);
RequestBody requestBody = new MultipartBody.Builder()
        .setType(MultipartBody.FORM)
        .addFormDataPart("file", file.getName(), fileBody)
        .build();

Request request = new Request.Builder()
        .url(url)
        .post(requestBody)
        .build();

client.newCall(request).enqueue(new Callback() {
    // ...
});

配置和拦截器

OkHttp 允许您配置连接参数和添加拦截器:

java 复制代码
OkHttpClient client = new OkHttpClient.Builder()
        .connectTimeout(10, TimeUnit.SECONDS)
        .readTimeout(10, TimeUnit.SECONDS)
        .writeTimeout(10, TimeUnit.SECONDS)
        .addInterceptor(new LoggingInterceptor())
        .build();

工具类

java 复制代码
/**
 * @author chenmeng
 */
@SuppressWarnings("all")
public class OkHttpUtil {

    private static final Logger logger = LoggerFactory.getLogger("okHttpReq");

    private static final long DEFAULT_TIMEOUT = 5000;
    private static final int MAX_IDLE_CONNECTION = 5;
    private static final long KEEP_ALIVE_DURATION = 1;
    public static final String JSON_CONTENT_TYPE = "application/json; charset=utf-8";
    public static final String FORM_CONTENT_TYPE = "application/x-www-form-urlencoded";

    private OkHttpUtil() {
        // 单例模式,防止外部实例化
    }

    private static final OkHttpClient HTTP_CLIENT = new OkHttpClient.Builder()
            .connectTimeout(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS)
            .readTimeout(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS)
            .writeTimeout(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS)
            .callTimeout(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS)
            .connectionPool(new ConnectionPool(MAX_IDLE_CONNECTION, KEEP_ALIVE_DURATION, TimeUnit.MINUTES))
            .build();

    /**
     * 发送GET请求
     *
     * @param url 请求URL
     * @return 响应结果字符串
     */
    public static String sendGet(String url) {
        return sendGetWithHeaders(url, null, null);
    }

    /**
     * 携带参数发送GET请求
     *
     * @param url   请求URL
     * @param param 请求参数
     * @return 响应结果字符串
     */
    public static String sendGetWithParam(String url, String param) {
        return sendGetWithHeaders(url, param, null);
    }

    /**
     * 携带请求头发送GET请求
     *
     * @param url     请求URL
     * @param param   请求参数
     * @param headers 请求头(可选)
     * @return 响应结果字符串
     */
    public static String sendGetWithHeaders(String url, String param, Map<String, String> headers) {
        String realUrl = url;
        if (StrUtil.isNotBlank(param)) {
            realUrl = url + "?" + param;
        }
        Request.Builder builder = new Request.Builder()
                .url(realUrl)
                .header("accept", "*/*")
                .header("connection", "Keep-Alive")
                .get();
        if (headers != null) {
            for (Map.Entry<String, String> entry : headers.entrySet()) {
                builder.addHeader(entry.getKey(), entry.getValue());
            }
        }
        Request request = builder.build();

        try (Response response = HTTP_CLIENT.newCall(request).execute()) {
            if (response.isSuccessful()) {
                // 处理响应数据
                long time = response.receivedResponseAtMillis() - response.sentRequestAtMillis();
                String result = response.body() != null ? response.body().string() : null;
                printRequestLog(url, null, param, time, result);
                return result;
            } else {
                // 处理错误响应
                // return response.toString();
                throw new IOException(String.valueOf(response));
            }
        } catch (Exception e) {
            // 处理网络异常
            logger.error("invoke Remote 【GET】 Method exception!== url【{}】,param【{}】", url, param);
            return returnErrorResult("远程请求失败:" + e.getMessage()).toString();
        }
    }

    /**
     * 发送POST请求(application/json; charset=utf-8)
     *
     * @param url   请求URL
     * @param param JSON字符串请求体
     * @return 响应结果字符串
     */
    public static String sendPostJson(String url, String param) {
        return sendPostJsonWithHeaders(url, param, null);
    }

    /**
     * 携带请求头发送POST请求(application/json)
     *
     * @param url     请求URL
     * @param param   JSON字符串请求体
     * @param headers 请求头(可选)
     * @return 响应结果字符串
     */
    public static String sendPostJsonWithHeaders(String url, String param, Map<String, String> headers) {
        MediaType mediaType = MediaType.parse(JSON_CONTENT_TYPE);
        RequestBody requestBody = RequestBody.create(param, mediaType);

        Request.Builder builder = new Request.Builder()
                .url(url)
                .header("accept", "*/*")
                .header("connection", "Keep-Alive")
                .header("Content-Type", JSON_CONTENT_TYPE)
                .post(requestBody);

        if (headers != null) {
            for (Map.Entry<String, String> entry : headers.entrySet()) {
                builder.addHeader(entry.getKey(), entry.getValue());
            }
        }
        Request request = builder.build();

        try (Response response = HTTP_CLIENT.newCall(request).execute()) {
            if (response.isSuccessful()) {
                // 处理响应数据
                long time = response.receivedResponseAtMillis() - response.sentRequestAtMillis();
                String result = response.body() != null ? response.body().string() : null;
                printRequestLog(url, JSON_CONTENT_TYPE, param, time, result);
                return result;
            } else {
                // 处理错误响应
                throw new IOException(String.valueOf(response));
            }
        } catch (Exception e) {
            // 处理网络异常
            logger.error("invoke Remote 【POST】 Method exception!== url【{}】,param【{}】", url, param, e);
            return returnErrorResult("Remote Request Fail--" + e.getMessage()).toString();
        }
    }

    /**
     * 发送POST请求(application/x-www-form-urlencoded)
     *
     * @param url    请求URL
     * @param params 请求参数(可选)
     * @return 响应结果字符串
     */
    public static String sendPostForm(String url, Map<String, Object> params) {
        return sendPostFormWithHeaders(url, params, null);
    }

    /**
     * 携带请求头发送POST请求(application/x-www-form-urlencoded)
     *
     * @param url     请求URL
     * @param params  请求参数(可选)
     * @param headers 请求头(可选)
     * @return 响应结果字符串
     */
    public static String sendPostFormWithHeaders(String url, Map<String, Object> params,
                                                 Map<String, String> headers) {
        RequestBody formBody;
        StringBuilder strParamsBuilder = new StringBuilder();
        if (params != null && !params.isEmpty()) {
            FormBody.Builder formBuilder = new FormBody.Builder();
            for (Map.Entry<String, Object> entry : params.entrySet()) {
                formBuilder.add(entry.getKey(), entry.getValue().toString());
            }
            formBody = formBuilder.build();
            // 打印参数
            for (Map.Entry<String, Object> e : params.entrySet()) {
                strParamsBuilder.append(e.getKey()).append("=").append(e.getValue()).append("&");
            }
        } else {
            // 若无参数,创建一个空的FormBody
            formBody = new FormBody.Builder().build();
        }
        String strParams = strParamsBuilder.toString();

        Request.Builder builder = new Request.Builder()
                .url(url)
                .header("accept", "*/*")
                .header("connection", "Keep-Alive")
                .header("Content-Type", FORM_CONTENT_TYPE)
                .post(formBody);

        if (headers != null) {
            for (Map.Entry<String, String> entry : headers.entrySet()) {
                builder.addHeader(entry.getKey(), entry.getValue());
            }
        }
        Request request = builder.build();

        try (Response response = HTTP_CLIENT.newCall(request).execute()) {
            if (response.isSuccessful()) {
                // 处理响应数据
                long time = response.receivedResponseAtMillis() - response.sentRequestAtMillis();
                String result = response.body() != null ? response.body().string() : null;
                printRequestLog(url, FORM_CONTENT_TYPE, strParams, time, result);
                return result;
            } else {
                // 处理错误响应
                throw new IOException(String.valueOf(response));
            }
        } catch (Exception e) {
            // 处理网络异常
            logger.error("invoke Remote 【POST】 Method exception!== url【{}】,param【{}】", url, strParams);
            return returnErrorResult("Remote Request Fail :" + e.getMessage()).toString();
        }
    }

    public static void printRequestLog(
            String url, String contentType, String data, Long time, String result) {
        // if (StrUtil.isNotBlank(result) && result.length() > 200) {
        //     result = result.substring(0, 200) + "...";
        // }
        String log =
                "\n================== Remote Request info ==================\n"
                        + String.format("Request URL: %s \n", url)
                        + String.format("Request Content-Type: %s\n", contentType)
                        + String.format("Request Parameter: %s \n", data)
                        + String.format("Request Time: %s ms \n", time)
                        + String.format("Response Result: %s \n", result)
                        + "================== Remote Request info ==================\n";
        logger.info(log);
    }

    public static JSONObject returnErrorResult(String msg) {
        JSONObject jsonObject = new JSONObject();
        jsonObject.putOpt("code", 1);
        jsonObject.putOpt("msg", msg);
        jsonObject.putOpt("data", null);
        return jsonObject;
    }
}

结论

OkHttp 是一个功能强大且易于使用的 HTTP 客户端,它提供了丰富的功能来满足各种网络请求的需求。无论是简单的 GET 请求还是复杂的文件上传,OkHttp 都能够提供高效的解决方案。通过上述示例,您可以快速地在自己的应用程序中使用 OkHttp 进行网络通信。

学习参考

相关推荐
洛克大航海8 小时前
Ajax基本使用
java·javascript·ajax·okhttp
whltaoin6 天前
Java 网络请求 Jar 包选型指南:从基础到实战
java·http·okhttp·网络请求·retrofit
华农第一蒟蒻7 天前
谈谈跨域问题
java·后端·nginx·安全·okhttp·c5全栈
一直向钱9 天前
android 基于okhttp的socket封装
android·okhttp
linuxxx1109 天前
ajax回调钩子的使用简介
okhttp
一直向钱10 天前
android 基于okhttp 封装一个websocket管理模块,方便开发和使用
android·websocket·okhttp
linuxxx11011 天前
ajax() 回调函数参数详解
前端·ajax·okhttp
linuxxx11013 天前
ajax与jQuery是什么关系?
ajax·okhttp·jquery
耀耀_很无聊15 天前
12_OkHttp初体验
okhttp
heeheeai15 天前
okhttp使用指南
okhttp·kotlin·教程