|
@@ -0,0 +1,114 @@
|
|
|
|
|
+package space.anyi.httpClient;
|
|
|
|
|
+
|
|
|
|
|
+import java.io.IOException;
|
|
|
|
|
+import java.net.CookieManager;
|
|
|
|
|
+import java.net.ProxySelector;
|
|
|
|
|
+import java.net.URI;
|
|
|
|
|
+import java.net.http.HttpClient;
|
|
|
|
|
+import java.net.http.HttpRequest;
|
|
|
|
|
+import java.net.http.HttpResponse;
|
|
|
|
|
+import java.net.http.HttpResponse.BodyHandlers;
|
|
|
|
|
+import java.time.Duration;
|
|
|
|
|
+import java.util.concurrent.Executors;
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * HTTP Client 配置项示例
|
|
|
|
|
+ *
|
|
|
|
|
+ * <p>通过 {@code HttpClient.newBuilder()} 返回的 Builder 可以配置客户端的
|
|
|
|
|
+ * 通用行为,主要配置项如下:</p>
|
|
|
|
|
+ *
|
|
|
|
|
+ * <table>
|
|
|
|
|
+ * <tr><th>配置项</th><th>作用</th><th>备注</th></tr>
|
|
|
|
|
+ * <tr><td>version()</td><td>HTTP 协议版本</td><td>HTTP_1_1 / HTTP_2</td></tr>
|
|
|
|
|
+ * <tr><td>connectTimeout()</td><td>连接建立超时时间</td><td>超过则抛 ConnectTimeoutException</td></tr>
|
|
|
|
|
+ * <tr><td>executor()</td><td>异步请求使用的线程池</td><td>不设置则用内置默认线程池</td></tr>
|
|
|
|
|
+ * <tr><td>followRedirects()</td><td>重定向策略</td><td>NEVER / ALWAYS / NORMAL</td></tr>
|
|
|
|
|
+ * <tr><td>proxy()</td><td>代理选择器</td><td>NO_PROXY 直连</td></tr>
|
|
|
|
|
+ * <tr><td>cookieHandler()</td><td>Cookie 管理器</td><td>配合 CookieManager 使用</td></tr>
|
|
|
|
|
+ * <tr><td>authenticator()</td><td>认证器</td><td>配合 Authenticator 使用(Basic Auth 等)</td></tr>
|
|
|
|
|
+ * <tr><td>sslContext/sslParameters()</td><td>TLS 配置</td><td>仅 HTTPS 生效</td></tr>
|
|
|
|
|
+ * <tr><td>priority()</td><td>HTTP/2 流优先级</td><td>仅 HTTP_2 生效</td></tr>
|
|
|
|
|
+ * </table>
|
|
|
|
|
+ */
|
|
|
|
|
+public class ClientConfigExample {
|
|
|
|
|
+
|
|
|
|
|
+ /** 服务基地址常量 */
|
|
|
|
|
+ private static final String BASE_URL = "http://localhost:8080";
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 构建一个携带多项配置的 HttpClient。
|
|
|
|
|
+ *
|
|
|
|
|
+ * <p>所有配置均为「在客户端创建时一次性设定」,创建后不可修改。</p>
|
|
|
|
|
+ *
|
|
|
|
|
+ * @return 配置完善的 HttpClient
|
|
|
|
|
+ */
|
|
|
|
|
+ public HttpClient buildConfiguredClient() {
|
|
|
|
|
+ // Cookie 管理器(Index: CookieManager 负责保存/发送 Cookie)
|
|
|
|
|
+ CookieManager cookieManager = new CookieManager();
|
|
|
|
|
+
|
|
|
|
|
+ return HttpClient.newBuilder()
|
|
|
|
|
+ // 指定 HTTP 协议版本为 1.1(本服务仅支持 HTTP/1.1)
|
|
|
|
|
+ .version(HttpClient.Version.HTTP_1_1)
|
|
|
|
|
+ // 连接建立超过 5 秒未成功则失败
|
|
|
|
|
+ .connectTimeout(Duration.ofSeconds(5))
|
|
|
|
|
+ // 自定义异步任务的执行线程池(默认是内置线程池)
|
|
|
|
|
+ .executor(Executors.newFixedThreadPool(4))
|
|
|
|
|
+ // 重定向策略:NORMAL 只自动跟随「安全方法」的重定向
|
|
|
|
|
+ .followRedirects(HttpClient.Redirect.NORMAL)
|
|
|
|
|
+ // 不使用代理,直连
|
|
|
|
|
+ .proxy(ProxySelector.getDefault())
|
|
|
|
|
+ // 配置 Cookie 管理器,自动管理会话 Cookie
|
|
|
|
|
+ .cookieHandler(cookieManager)
|
|
|
|
|
+ .build();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 构建启用 HTTP/2 的客户端(本服务不支持,仅演示配置写法)。
|
|
|
|
|
+ */
|
|
|
|
|
+ public HttpClient buildHttp2Client() {
|
|
|
|
|
+ return HttpClient.newBuilder()
|
|
|
|
|
+ .version(HttpClient.Version.HTTP_2)
|
|
|
|
|
+ // priority 仅对 HTTP/2 生效,范围 1~256,越大优先级越高
|
|
|
|
|
+ .priority(256)
|
|
|
|
|
+ .build();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 使用配置好的客户端发送 GET 请求。
|
|
|
|
|
+ *
|
|
|
|
|
+ * @return GET /api/users 的响应
|
|
|
|
|
+ */
|
|
|
|
|
+ public HttpResponse<String> sendGet() throws IOException, InterruptedException {
|
|
|
|
|
+ HttpClient httpClient = buildConfiguredClient();
|
|
|
|
|
+
|
|
|
|
|
+ HttpRequest request = HttpRequest.newBuilder()
|
|
|
|
|
+ .uri(URI.create(BASE_URL + "/api/users"))
|
|
|
|
|
+ .GET()
|
|
|
|
|
+ .build();
|
|
|
|
|
+
|
|
|
|
|
+ return httpClient.send(request, BodyHandlers.ofString());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 演示「连接超时」配置:连接不存在的地址应快速失败并抛异常。
|
|
|
|
|
+ */
|
|
|
|
|
+ public void demoConnectTimeout() {
|
|
|
|
|
+ HttpClient client = HttpClient.newBuilder()
|
|
|
|
|
+ .connectTimeout(Duration.ofSeconds(2))
|
|
|
|
|
+ .build();
|
|
|
|
|
+
|
|
|
|
|
+ HttpRequest request = HttpRequest.newBuilder()
|
|
|
|
|
+ // 使用一个不存在的端口,模拟连接超时
|
|
|
|
|
+ .uri(URI.create("http://localhost:9999"))
|
|
|
|
|
+ .GET()
|
|
|
|
|
+ .build();
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ client.send(request, BodyHandlers.ofString());
|
|
|
|
|
+ } catch (java.net.http.HttpConnectTimeoutException e) {
|
|
|
|
|
+ System.out.println("连接超时: " + e.getMessage());
|
|
|
|
|
+ } catch (IOException | InterruptedException e) {
|
|
|
|
|
+ System.out.println("请求异常: " + e.getMessage());
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|