前言
OkHttp是一个基于HTTP的用于访问网络服务的Java库。它旨在通过取消HTTP连接池以及支持连接和请求超时来提高性能。它还支持SSL和TLS,以及HTTP/2和HTTP/3。OkHttp提供了连接管理器、请求对象、缓存以及响应对象等工具,以便开发人员可以轻松地执行HTTP请求和响应。
在传统的单体应用开发中,后端常常作为接收请求的一端。但当我们需要依赖于另一个应用,比如连接工作流的时候,需要后端来发送请求。如果没有做过网络编程,这是个很令人困扰的问题。那么就有了这样一种方便使用的框架:OKHttp。
一. 慢速入门
场景:模拟一个请求发出后,client
端接收并向server
端发起请求。
1.1 准备两个Spring boot工程
父工程pom
文件,省略部分
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.1.4</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<modules>
<module>server</module>
<module>client</module>
</modules>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
client
端的pom引入OKHttp
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.10.0</version>
</dependency>
1.2 核心代码
client
端,/controller/HelloController
@GetMapping("/hello")
@ResponseBody
public String hello() {
OkHttpClient client = new OkHttpClient();
// 请求参数
Request request = new Request.Builder()
.url("http://localhost:8080/client")
.build();
// 返回结果
String result = "";
try (Response response = client.newCall(request).execute()) {
if (response.isSuccessful()) {
result = response.body().string();
} else {
result = STR."请求失败: {response.message()}";
}
} catch (IOException e) {
result = STR."请求失败: {e}";
}
return result;
}
server
端,/controller/AnswerClient
@GetMapping("/client")
@ResponseBody
public String hello(String msg) {
return "我很好";
}
1.3 测试
使用curl
命令发起请求
curl http://localhost:8082/hello
结果
二. 浅入应用
2. 1 更多参数
核心代码中构建一个request对象为参数,在使用的时候发现,有更多的属性可以加入。
代码语言:java复制class Request internal constructor(
@get:JvmName("url") val url: HttpUrl,
@get:JvmName("method") val method: String,
@get:JvmName("headers") val headers: Headers,
@get:JvmName("body") val body: RequestBody?,
internal val tags: Map<Class<*>, Any>
- url: 目标服务地址
- method:请求方法
- head:请求头
- body:请求参数
简单post示例
代码语言:java复制Request request = new Request.Builder()
.url(url)
.header("name", "value")
.post(requestBody)
.build();
2.2 泛化调用
目标:我们通过“一个”URL访问不同的REST接口
代码语言:java复制final static String WORK_FLOW_URL = "http://localhost:8080/workflow/{0}/{1}"
看起来只是少些一些代码,其更多意义是针对业务做再封装。
更多重点是另一方的统一实现接口,使得更加灵活。
2.3 序列化参数
有些时候需要的参数很多,层级关系复杂,这时候往往需要序列化成json。
拿fastjson
举例。
Person person = new Person("张三", 18);
String jsonString = JSON.toJSONString(person); // {"age":18,"name":"张三"}
2.4 请求重试
这次从OKHttp的构建出发。主要思路是加入自定义拦截器。代码如下:
代码语言:java复制 HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient.Builder builder = new OkHttpClient.Builder()
.addInterceptor(loggingInterceptor)
.addInterceptor(new RetryInterceptor())
.retryOnConnectionFailure(true);
自定义的拦截器。
代码语言:java复制public class RetryInterceptor implements Interceptor {
private static final int MAX_RETRIES = 3; // 设置最大重试次数
private int retries;
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Response response = chain.proceed(request);
if (!Objects.requireNonNull(response.body()).contentLength() > 0) {
return response;
}
while (!response.isSuccessful() && retries < MAX_RETRIES) {
retries ;
response = chain.proceed(request);
}
if (retries == MAX_RETRIES) {
throw new IOException("请求失败,已达到最大重试次数");
}
return response;
}
}
测试使用
代码语言:java复制 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 {
if (!response.isSuccessful()) {
throw new IOException("请求失败,代码:" response.code());
}
// 处理响应
System.out.println(response.body().string());
}
});
总结
这只是使用了一部分,框架还提供了:多种协议,连接池,缓存,同步异步等处理。有点初具RPC的影子。在简单的场景,是很好的RPC的替代。
我正在参与2023腾讯技术创作特训营第二期有奖征文,瓜分万元奖池和键盘手表