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() {@Overridepublic void onFailure(Call call, IOException e) {// 网络请求失败}@Overridepublic 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() {@Overridepublic void onFailure(Call call, IOException e) {// 网络请求失败}@Overridepublic 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 {// 若无参数,创建一个空的FormBodyformBody = 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 进行网络通信。
学习参考
- 官方文档
- 七大主流的HttpClient程序比较 - 知乎 (zhihu.com)
- Okhttp3基本使用 - 简书 (jianshu.com)