OkHttpClient使用详解,及使用连接池的OkHttpUtils工具类
HTTP是现代应用程序联网的方式。这是我们交换数据和媒体的方式。高效地使用HTTP可以使您的内容加载更快,并节省带宽。
OkHttp是一个HTTP客户端,默认情况下是高效的:
- HTTP/2支持允许对同一主机的所有请求共享一个套接字。
- 连接池可以减少请求延迟(如果HTTP/2不可用)。
- 透明GZIP压缩下载大小。
- 响应缓存完全避免了重复请求的网络。
当网络出现问题时,OkHttp会坚持下去:它会从常见的连接问题中静默地恢复。如果您的服务有多个IP地址,如果第一次连接失败,OkHttp将尝试替代地址。这对于IPv4+IPv6以及托管在冗余数据中心的业务是必要的。OkHttp支持现代TLS特性(TLS 1.3, ALPN,证书固定)。它可以配置为后退以获得广泛连接。
使用OkHttp很简单。它的请求/响应API采用流畅构建器和不可变设计。它既支持同步阻塞调用,也支持带回调的异步调用。
github链接地址: (GitHub - square/okhttp: Square’s meticulous HTTP client for the JVM, Android, and GraalVM.)
官方项目地址:[Overview - OkHttp (square.github.io)](https://square.github.io/okhttp/)
请求方法详解
我们编写了一些方法,演示如何使用 OkHttp 解决常见问题。通读它们,了解一切如何协同工作。自由剪切和粘贴这些示例;这就是他们的目的。
Get
import java.io.IOException;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
public class GetExample {
final OkHttpClient client = new OkHttpClient();
String run(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 void main(String[] args) throws IOException {
GetExample example = new GetExample();
String response = example.run("https://raw.github.com/square/okhttp/master/README.md");
System.out.println(response);
}
}
POST
import java.io.IOException;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
public class PostExample {
public static final MediaType JSON = MediaType.get("application/json; charset=utf-8");
final OkHttpClient client = new OkHttpClient();
String post(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();
}
}
String bowlingJson(String player1, String player2) {
return "{'winCondition':'HIGH_SCORE',"
+ "'name':'Bowling',"
+ "'round':4,"
+ "'lastSaved':1367702411696,"
+ "'dateStarted':1367702378785,"
+ "'players':["
+ "{'name':'" + player1 + "','history':[10,8,6,7,8],'color':-13388315,'total':39},"
+ "{'name':'" + player2 + "','history':[6,10,5,10,10],'color':-48060,'total':41}"
+ "]}";
}
public static void main(String[] args) throws IOException {
PostExample example = new PostExample();
String json = example.bowlingJson("Jesse", "Jake");
String response = example.post("http://www.roundsapp.com/post", json);
System.out.println(response);
}
}
Asynchronous Get
OkHttp提供enqueue
方法来异步执行请求,并提供一个Callback
方法来处理回调。
案例:在工作线程上下载一个文件,并在响应可读时返回。回调是在响应标头准备好之后执行的,读取响应体可能仍然会阻塞。OkHttp现阶段不提供异步api来接收响应体。
private final OkHttpClient client = new OkHttpClient();
public void run() throws Exception {
Request request = new Request.Builder()
.url("http://publicobject.com/helloworld.txt")
.build();
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 responseBody = response.body()) {
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
Headers responseHeaders = response.headers();
for (int i = 0, size = responseHeaders.size(); i < size; i++) {
System.out.println(responseHeaders.name(i) + ": " + responseHeaders.value(i));
}
System.out.println(responseBody.string());
}
}
});
}
上述简单介绍了主要的几种请求方式的案例,其它的请求方式皆可根据上述进行眼神。
更多案例详情,比如Post方式提交String, Post方式提交流,响应缓存等,可以参考官网的请求案例讲解:
[Recipes - OkHttp (square.github.io)](https://square.github.io/okhttp/recipes/)
OkHttpUtils工具类
@Slf4j
public class OkHttpUtils {
// 方式一
private static OkHttpClient okHttpClient = null;
public static OkHttpClient getOkHttpClient(){
if (okHttpClient != null){
return okHttpClient;
}
// 加锁
synchronized (OkHttp3Demo.class){
// 自定义连接池最大空闲连接数和等待时间大小,否则默认最大10个空闲连接
ConnectionPool connectionPool = new ConnectionPool(32, 10, TimeUnit.MINUTES);
okHttpClient = new OkHttpClient.Builder()
.connectTimeout(30, TimeUnit.SECONDS) // 连接超时
.writeTimeout(20,TimeUnit.SECONDS) // 写入超时
.readTimeout(20,TimeUnit.SECONDS) // 读取超时
.connectionPool(connectionPool) //
// .addInterceptor() 添加应用拦截器
// .addNetworkInterceptor() 添加网络拦截器
// .cache() 设置缓存
.build();
}
return client;
}
// 创建OkHttpClient对象, 并设置超时时间
private static final OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(30, TimeUnit.SECONDS)
.build();
/**
* 同步GET请求
*
* @param url 请求地址
*/
public static String getRequest(String url) {
try {
// 1 创建OkHttpClient对象
// 2 构建Request对象
Request request = new Request.Builder()
.get()// 不写默认为GET请求
.url(url)
.build();
// 3 发起请求获取响应值
Response response = client.newCall(request).execute();
// 4 根据响应结果判断
if (response.isSuccessful()) {
return response.body().string();
} else {
throw new RuntimeException("请求异常,错误码为: " + response.code());
}
} catch (Exception e) {
log.info("请求失败,错误信息为= {} ", e.getMessage());
}
return null;
}
/**
* 同步POST请求
*
* @param url 请求地址
* @param params 请求参数
*/
public static String postRequest(String url, Map<String, String> params) {
try {
// 1 创建OkHttpClient对象
// 2 构建请求体
MultipartBody body = new MultipartBody.Builder()
.setType(MediaType.parse("multipart/form-data"))
.addFormDataPart("username", params.get("username"))
.addFormDataPart("password", params.get("password"))
.build();
// 3 构建Request对象
Request request = new Request.Builder()
.post(body)
.url(url)
.build();
// 4 发起请求获取响应值
Response response = client.newCall(request).execute();
// 5 根据响应结果判断
if (response.isSuccessful()) {
return response.body().string();
} else {
throw new RuntimeException("请求异常,错误码为: " + response.code());
}
} catch (Exception e) {
log.info("请求失败,错误信息为= {} ", e.getMessage());
}
return null;
}
/**
* 同步GET请求
*/
public static String getRequest(String url) throws IOException {
Request request = new Builder().url(url).build();
Response response = execute(request);
if (response.isSuccessful()) {
return response.body().string();
} else {
throw new ArithmeticException("请求异常,错误码为: " + response.code());
}
}
/**
* 同步请求
*/
public static Response execute(Request request) throws IOException {
return client.newCall(request).execute();
}
/**
* 开启异步线程访问网络, 需要返回结果
*/
public static void enqueue(Request request, Callback callback) {
client.newCall(request).enqueue(callback);
}
/**
* 开启异步线程访问网络,不需要返回结果( Callback 返回为空)
*/
public static void enqueue(Request request) {
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(@NotNull Call call, @NotNull IOException e) {
log.info("请求失败,异常信息为: {} ", e.getMessage());
}
@Override
public void onResponse(@NotNull Call call, @NotNull Response response)
throws IOException {
log.info("请求成功");
}
});
}
}
参考文献: