使用 OkHttp 调用接口
🏷️ OkHttp
OkHttp 是一款很强大的网络请求框架。这里学习下如何通过其 OkHttpClient
来发送网络请求。
假设有如下接口:
请求类型 | URL | 说明 |
---|---|---|
GET | /hello | 没有参数 |
GET | /hello/{name} | 从 URL 的 Path 中获取参数 |
POST | /hello | 从 POST 请求的 Body 中获取参数 |
POST | /hello/from-header | 从 Header 中获取参数 |
对应的 HelloController
的代码和这篇博客中的一样,这里就不再重复了。
使用 OkHttp 调用接口的示例代码(测试类):
java
package me.liujiajia.springboot.advanced.ok.http.controller;
import com.fasterxml.jackson.databind.ObjectMapper;
import okhttp3.*;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.HttpStatus;
import java.io.IOException;
import java.util.Objects;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
class HelloControllerTest {
public static final String NAME = "JiaJia";
public static final MediaType JSON = MediaType.get("application/json; charset=utf-8");
@Autowired
private OkHttpClient client;
@Test
void sayHello() throws IOException {
Request request = new Request.Builder()
.url("http://localhost:8080/hello")
.build();
try (Response response = client.newCall(request).execute()) {
Assertions.assertEquals(response.code(), HttpStatus.OK.value());
Assertions.assertEquals(Objects.requireNonNull(response.body()).string(), "Hello,World!");
}
}
@Test
void sayHelloWithName() throws IOException {
Request request = new Request.Builder()
.url(String.format("http://localhost:8080/hello/%s", NAME))
.build();
try (Response response = client.newCall(request).execute()) {
Assertions.assertEquals(response.code(), HttpStatus.OK.value());
Assertions.assertEquals(Objects.requireNonNull(response.body()).string(), String.format("Hello,%s!", NAME));
}
}
@Test
void sayHelloWithUserInfo() throws IOException {
HelloController.UserInfo userInfo = new HelloController.UserInfo();
userInfo.setName(NAME);
ObjectMapper objectMapper = new ObjectMapper();
String json = objectMapper.writeValueAsString(userInfo);
RequestBody body = RequestBody.create(json, JSON);
Request request = new Request.Builder()
.url("http://localhost:8080/hello")
.post(body)
.build();
try (Response response = client.newCall(request).execute()) {
Assertions.assertEquals(response.code(), HttpStatus.OK.value());
Assertions.assertEquals(Objects.requireNonNull(response.body()).string(), String.format("Hello,%s!", NAME));
}
}
@Test
void sayHelloWithHeader() throws IOException {
Request request = new Request.Builder()
.url("http://localhost:8080/hello/from-header")
.header("name", NAME)
.post(RequestBody.create("{}", JSON))
.build();
try (Response response = client.newCall(request).execute()) {
Assertions.assertEquals(response.code(), HttpStatus.OK.value());
Assertions.assertEquals(Objects.requireNonNull(response.body()).string(), String.format("Hello,%s!", NAME));
}
}
}
更多 OkHttp 的用法见官方的 Recipes。
在 SpringBoot 中使用时需要添加 okhttp 依赖,这里使用的是当前的最新版 4.10.0 。
xml
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.10.0</version>
</dependency>
OkHttpClient
的配置类(参考这篇博客):
java
package me.liujiajia.springboot.advanced.ok.http.config;
import okhttp3.ConnectionPool;
import okhttp3.OkHttpClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.concurrent.TimeUnit;
/**
* @author 佳佳
*/
@Configuration
public class OkHttpClientConfig {
@Value("${ok.http.connect-timeout:10}")
private Integer connectTimeout;
@Value("${ok.http.read-timeout:10}")
private Integer readTimeout;
@Value("${ok.http.write-timeout:10}")
private Integer writeTimeout;
@Value("${ok.http.max-idle-connections:5}")
private Integer maxIdleConnections;
@Value("${ok.http.keep-alive-duration:5}")
private Long keepAliveDuration;
@Bean
public OkHttpClient okHttpClient() {
return new OkHttpClient().newBuilder()
.connectionPool(connectionPool())
.connectTimeout(connectTimeout, TimeUnit.SECONDS)
.readTimeout(readTimeout, TimeUnit.SECONDS)
.writeTimeout(writeTimeout, TimeUnit.SECONDS)
.hostnameVerifier((hostname, session) -> true)
// 设置代理
// .proxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress("127.0.0.1", 8888)))
// 拦截器
// .addInterceptor()
.build();
}
private ConnectionPool connectionPool() {
return new ConnectionPool(maxIdleConnections, keepAliveDuration, TimeUnit.MINUTES);
}
}
如果希望 RestTemplate
使用 OkHttpClient
(默认是 HttpClient
)发送网络请求,可以通过如下方式配置:
java
package me.liujiajia.springboot.advanced.ok.http.config;
import okhttp3.OkHttpClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.OkHttp3ClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
/**
* @author 佳佳
*/
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate(ClientHttpRequestFactory clientHttpRequestFactory) {
RestTemplate restTemplate = new RestTemplate(clientHttpRequestFactory);
// 可以添加消息转换
//restTemplate.setMessageConverters(...);
// 可以增加拦截器
//restTemplate.setInterceptors(...);
return restTemplate;
}
@Bean
public ClientHttpRequestFactory clientHttpRequestFactory(OkHttpClient okHttpClient) {
return new OkHttp3ClientHttpRequestFactory(okHttpClient);
}
}