最佳实践
零依赖使用
有时候希望零依赖进行HTTP
调用,下面是一个发送钉钉机器人的消息的一个例子:
private static final String URL = "https://oapi.dingtalk.com/robot/send?access_token=${YOUR_ACCESS_TOKEN}";
String content = "{\"msgtype\":\"text\",\"text\":{\"content\":\"hello, world\"}}";
SolpicTemplate solpicTemplate = Solpic.newSolpicTemplate();
HttpResponse<String> response = solpicTemplate.post(URL, content, String.class);
System.out.println(response.getStatusCode());
System.out.println(response.getPayload());
如果调用成功的话,会输出如下结果:
OK
{"errcode":0,"errmsg":"ok"}
零依赖使用在JDK[8,10]
会选用HttpURLConnection
进行真正的HTTP
调用,而在JDK[11
会选用java.net.http.HttpClient
进行真正的HTTP
调用。HttpURLConnection
不支持连接池配置,java.net.http.HttpClient
本身没有显式的连接池管理API
,但其内部实现了连接池并且默认启用。
TIP
java.net.http.HttpClient
提供了系统变量用于配置连接池的属性:
jdk.httpclient.connectionPoolSize
:用于配置连接池的容量,默认是0
,也就是无限制jdk.httpclient.keepalive.timeout
:连接保活过期时间,默认是1200
(单位是秒,也就是20
分钟)
Solpic
初始化底层客户端为java.net.http.HttpClient
的时候会尝试捕获这两个值并且尝试基于配置值改变这两个系统变量,但是不确保会生效。
第三方客户端
使用Apache HTTP Client5
,需要引入以下依赖:
<dependency>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5</artifactId>
<version>5.3.1</version>
</dependency>
implementation 'org.apache.httpcomponents.client5:httpclient5:5.3.1'
构建HttpClient
实例的时候需要指定类型为APACHE_HTTPCLIENT_V5(ahc5)
:
HttpClient httpClient = Solpic.newHttpClientBuilder()
.type(HttpClientType.APACHE_HTTPCLIENT_V5)
.build();
System.out.println(httpClient.id());
使用Apache HTTP Client
,需要引入以下依赖:
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.14</version>
</dependency>
implementation 'org.apache.httpcomponents:httpclient:4.5.14'
构建HttpClient
实例的时候需要指定类型为APACHE_HTTPCLIENT_V4(ahc4)
:
HttpClient httpClient = Solpic.newHttpClientBuilder()
.type(HttpClientType.APACHE_HTTPCLIENT_V4)
.build();
System.out.println(httpClient.id());
使用OkHttp
,需要引入以下依赖:
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.12.0</version>
</dependency>
implementation 'com.squareup.okhttp3:okhttp:4.12.0'
构建HttpClient
实例的时候需要指定类型为OKHTTP(okhttp)
:
HttpClient httpClient = Solpic.newHttpClientBuilder()
.type(HttpClientType.OKHTTP)
.build();
System.out.println(httpClient.id());
启用连接池
Solpic
所支持的底层HTTP
客户端实现之中只有HttpURLConnection
不支持连接池配置,因此选用了其他底层客户端实现建议启用连接池特性。例如:
private static final String URL = "https://oapi.dingtalk.com/robot/send?access_token=${YOUR_ACCESS_TOKEN}";
String content = "{\"msgtype\":\"text\",\"text\":{\"content\":\"hello, world\"}}";
HttpClient httpClient = Solpic.newHttpClientBuilder()
.type(HttpClientType.APACHE_HTTPCLIENT_V5)
.option(HttpOptions.HTTP_CLIENT_ENABLE_CONNECTION_POOL, true)
.option(HttpOptions.HTTP_CLIENT_CONNECTION_POOL_CAPACITY, 128)
.option(HttpOptions.HTTP_CLIENT_CONNECTION_TTL, 1800000)
.build();
SolpicTemplate solpicTemplate = Solpic.newSolpicTemplateBuilder()
.httpClient(httpClient)
.codec(Solpic.loadCodec())
.build();
HttpResponse<String> response = solpicTemplate.post(URL, content, String.class);
System.out.println(response.getStatusCode());
System.out.println(response.getPayload());
启用虚拟线程
见高级特性 - 启用虚拟线程小节。
声明式使用
现实中绝大部分的声明式使用场景都是同步调用,并且请求或者响应对象都是支持序列化和反序列化的简单对象,针对这个场景可以使用CodecConverterFactory
基于编码解码器完成API
的请求参数和响应结果转换。举个例子:
@Data
public class HttpBinResult {
private Map<String, String> args;
private Map<String, String> headers;
private Map<String, Object> json;
private String origin;
private String url;
}
public interface SyncHttpBinApi {
@Get(path = "/get")
HttpBinResult get(@Query("foo") String fooVal);
@Post(path = "/post")
HttpBinResult post(@Payload Map<String, String> payload);
}
编写客户端API
调用代码:
public static void main(String[] args) {
SyncHttpBinApi api = ApiEnhancerBuilder.newBuilder()
.httpClient(Solpic.newHttpClientBuilder().type(HttpClientType.JDK_HTTPCLIENT).build())
.addConverterFactory(CodecConverterFactory.newInstance(Solpic.loadCodec("jackson")))
.baseUrl("https://httpbin.org")
.build()
.enhance(SyncHttpBinApi.class);
HttpBinResult r1 = api.get("bar");
System.out.printf("get result => %s\n", r1);
HttpBinResult r2 = api.post(Collections.singletonMap("hello", "world"));
System.out.printf("post result => %s\n", r2);
}
某次执行结果如下:
get result => HttpBinResult(args={foo=bar}, headers={Host=httpbin.org, User-Agent=Java-http-client/22,
X-Amzn-Trace-Id=Root=1-66e262a8-6c9166a234faa02e2e442389}, json=null, origin=183.6.24.203, url=https://httpbin.org/get?foo=bar)
post result => HttpBinResult(args={}, headers={Host=httpbin.org, Transfer-Encoding=chunked, User-Agent=Java-http-client/22,
X-Amzn-Trace-Id=Root=1-66e262a9-475323555361295a0891c9f1}, json={hello=world}, origin=183.6.24.203, url=https://httpbin.org/post)