OkHttp使用详解及使用连接池的OkHttpUtils工具类
在现代应用程序中,HTTP是用于联网的主要方式。通过高效地使用HTTP,可以使内容加载更快,并节省带宽。
OkHttp是一个高效的HTTP客户端。默认情况下,它具有以下特点:
* 支持HTTP/2,允许对同一主机的所有请求共享一个套接字。
* 提供连接池功能,以减少请求延迟(如果HTTP/2不可用)。
* 能够透明地进行GZIP压缩下载,从而减小文件大小。
* 完全利用响应缓存,避免重复请求网络资源。
* 当网络出现问题时,OkHttp会自动恢复。例如,如果服务有多个IP地址,且第一次连接失败,OkHttp将尝试替代地址。对于托管在冗余数据中心的业务来说,这非常有用。同时,OkHttp支持现代TLS特性(如TLS 1.3、ALPN和证书固定),并且可以配置为后退以获得广泛连接。
使用OkHttp非常简单。其请求/响应API采用流畅的构建器和不可变设计。OkHttp既支持同步阻塞调用,也支持带回调的异步调用。
以下是官方项目地址:Overview - OkHttp (square.github.io)
请求方法详解
我们编写了一些示例代码,演示如何使用OkHttp解决常见问题。请仔细阅读这些示例,了解它们是如何协同工作的。您可以根据需要自由剪切和粘贴这些示例;这就是它们的目的。
## Get请求示例
```java
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
public class Main {
public static void main(String[] args) throws Exception {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("https://api.github.com/users/octocat")
.build();
Response response = client.newCall(request).execute();
System.out.println(response.body().string());
}
}
```
此示例中,我们创建了一个GET请求,访问了GitHub上Octocat用户的信息。运行这段代码后,您将在控制台看到返回的用户信息。
解:根据题意,可以得到以下结论:
(1) 点A在直线$y=-x+3$上,设$A(a,-a+3)$,则有$-a+3=2a$,解得$a=1$,所以$A(1,2)$。
(2) 点B在直线$y=x+1$上,设$B(b,b+1)$,则有$b+1=b+1$,此方程无解,所以点B不存在。
以下是重构后的代码:
```java
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");
private final OkHttpClient client = new OkHttpClient();
public 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();
}
}
private 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);
}
}
```
主要重构了以下内容:
将 `post` 方法中的字符串拼接替换为使用占位符的方式,以提高代码可读性和可维护性。
Asynchronous Get with enqueueCallback
在OkHttp中,我们可以使用enqueueCallback方法来实现异步的GET请求。这种方法允许我们在工作线程上下载文件,而不需要等待响应可读。回调函数将在响应标头准备好之后执行,但读取响应体仍然可能阻塞。需要注意的是,OkHttp目前还没有提供异步API来接收响应体。
## 代码示例
首先,我们需要创建一个`Request.Builder`对象,并设置请求的URL和HTTP方法。然后,我们使用`enqueueCallback`方法将请求添加到请求队列中。最后,我们定义回调函数,该函数将在请求完成时被调用。
```java
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
public class EnqueueCallbackExample {
public static void main(String[] args) {
OkHttpClient client = new OkHttpClient();
String url = "https://example.com/file";
Callback callback = new Callback() {
@Override
public void onFailure(Request request, IOException e) {
System.out.println("请求失败: " + e.getMessage());
}
@Override
public void onResponse(Call call, Response response) throws IOException {
if (response.isSuccessful()) {
System.out.println("请求成功: " + response.body().string());
} else {
System.out.println("请求失败: " + response.code());
}
}
};
Request request = new Request.Builder()
.url(url)
.build();
client.newCall(request).enqueue(callback);
}
}
```
在这个示例中,我们使用了`enqueue`方法而不是`enqueueCallback`方法。这是因为我们现在使用的是OkHttp的较旧版本,而这个方法是较新版本中的推荐用法。如果你使用的是较新版本的OkHttp,你应该直接使用`enqueueCallback`方法。
这段代码是一个简单的HTTP请求示例,它使用了OkHttp库。下面是重构后的代码:
```java
import okhttp3.*;
public class HttpClientExample {
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方式提交流,响应缓存等。
此外,OkHttpUtils工具类是一款基于 OkHttp 的封装库,由技术社区知名开发者 hongyangAndroid 创建并维护。它极大地简化了网络请求的过程,提供了简洁易用的API,允许开发者快速集成HTTP请求功能。
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;
}
private static final OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(30, TimeUnit.SECONDS)
.build();
/**
* 同步GET请求
* @param url 请求地址
*/
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());
}
}
/**
* 同步POST请求
* @param url 请求地址
* @param params 请求参数
*/
public static String postRequest(String url, Map
try {
MultipartBody body = new MultipartBody.Builder()
.setType(MediaType.parse("multipart/form-data"))
.addFormDataPart("username", params.get("username"))
.addFormDataPart("password", params.get("password"))
.build();
Request request = new Request.Builder()
.post(body)
.url(url)
.build();
Response response = execute(request);
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 Response execute(String url) throws Exception { Request request = new Builder().url(url).build(); Response response = client.newCall(request).execute(); return response; } /** * * 异步执行网络请求 */ /** * * @param request * @param callback * @throws Exception */ /** * 异步执行网络请求不带返回结果 */ /** * 异步执行网络请求不带返回结果 */ /** * 开启异步线程访问网络, 需要返回结果 */ /** * 开启异步线程访问网络,不需要返回结果(回调返回值为空) */
在撰写文献综述或者进行任何学术研究时,引用参考文献是非常重要的一部分。参考文献不仅可以证明你的研究基于可靠的来源,而且也可以提供进一步的阅读材料给读者。以下是一些关于如何正确地引用参考文献的建议:
1. 确保你理解了引用规则:不同的学科和出版物可能有不同的引用规则。例如,APA(美国心理学协会)和MLA(现代语言协会)是两种常见的引用风格。确保你了解并遵循你所在领域或出版物的具体规则。
2. 使用引文管理工具:引文管理工具如EndNote、Zotero和Mendeley可以帮助你管理和格式化你的引用。这些工具也可以帮助你在写作时自动插入正确的引用格式。
3. 在正文中明确引用来源:在你直接引用某项信息或观点的地方,你需要明确指出该信息的来源。这通常通过在句子中包含作者的名字、出版年份、文章标题和页码来完成。
4. 在参考文献列表中列出所有来源:在你的论文或报告的末尾,你需要提供一个完整的参考文献列表。这个列表应该按照你在正文中引用的顺序排列,每个来源都应该包括作者的名字、出版年份、文章标题、出版社和页码。
5. 仔细检查你的引用:最后,你需要仔细检查你的引用,确保它们都是准确的。错误的引用可能会导致抄袭的问题,所以在提交之前一定要进行校对。