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