OkHttp入门

OkHttp 简介与使用示例

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

为什么选择 OkHttp?

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

快速开始

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

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

同步 GET 请求

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

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 请求

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

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 请求并附带请求体:

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 也支持文件上传:

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 允许您配置连接参数和添加拦截器:

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

工具类

/**
 * @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 进行网络通信。

学习参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值