🔗 Vostok.Http
Http 客户端模块
统一 HTTP 客户端,支持命名 Client(baseUrl + 独立配置)、链式请求构建器、重试与指数退避、熔断器(Circuit Breaker)、舱壁(Bulkhead)、客户端限流、JSON 自动序列化/反序列化、流式响应、SSE 事件流、WebSocket、请求拦截器链、Cookie 管理、mTLS 以及请求指标统计。
初始化(可选)
零配置启动
// 无需显式初始化,首次请求时自动以默认配置启动
VKHttpResponse res = Vostok.Http.get("https://api.example.com/users").execute();
显式初始化
Vostok.Http.init(new VKHttpConfig()
.connectTimeoutMs(3000)
.totalTimeoutMs(10000)
.readTimeoutMs(0) // 0 = 不限制
.maxRetries(2)
.retryBackoffBaseMs(100)
.retryBackoffMaxMs(1000)
.retryJitterEnabled(true)
.retryOnStatuses(429, 502, 503, 504)
.retryMethods("GET", "HEAD", "PUT", "DELETE")
.failOnNon2xx(true)
.followRedirects(true)
.maxResponseBodyBytes(8 * 1024 * 1024) // 8MB
.userAgent("MyApp/1.0")
.metricsEnabled(true)
);
快速请求
GET
VKHttpResponse res = Vostok.Http.get("https://api.example.com/users")
.header("Accept", "application/json")
.execute();
System.out.println(res.statusCode() + " " + res.bodyText());
GET 并自动解析 JSON
User user = Vostok.Http.get("https://api.example.com/users/1")
.executeJson(User.class);
POST JSON
VKHttpResponse res = Vostok.Http.post("https://api.example.com/users")
.bodyJson(new User("alice", "alice@example.com"))
.execute();
User created = res.bodyJson(User.class);
表单提交(application/x-www-form-urlencoded)
VKHttpResponse res = Vostok.Http.post("https://example.com/login")
.form("username", "alice")
.form("password", "secret")
.execute();
// 或批量设置
Vostok.Http.post("https://example.com/form")
.form(Map.of("key1", "val1", "key2", "val2"))
.execute();
Multipart 上传
// 文本字段 + 文件字段混合
Vostok.Http.post("https://api.example.com/upload")
.multipart("description", "profile photo")
.multipart("file", "avatar.jpg", "image/jpeg", fileBytes)
.execute();
PUT / PATCH / DELETE / HEAD / OPTIONS
Vostok.Http.put("https://api.example.com/users/1")
.bodyJson(Map.of("name", "Bob"))
.execute();
Vostok.Http.patch("https://api.example.com/users/1")
.bodyJson(Map.of("email", "bob@example.com"))
.execute();
Vostok.Http.delete("https://api.example.com/users/1").execute();
Vostok.Http.head("https://api.example.com/users").execute();
Vostok.Http.request().options("https://api.example.com/users").execute();
请求构建器详解
URL 路径参数
// URL 模板中的 {userId} 被替换为实际值
Vostok.Http.get("https://api.example.com/users/{userId}/orders/{orderId}")
.path("userId", 42)
.path("orderId", 100)
.execute();
查询参数
// 单值查询参数
Vostok.Http.get("https://api.example.com/users")
.query("page", 1)
.query("size", 20)
.query("status", "active")
.execute();
// 多值查询参数(同名多值)
Vostok.Http.get("https://api.example.com/items")
.query("ids", List.of("1", "2", "3"))
.execute();
请求头
Vostok.Http.get("https://api.example.com/data")
.header("X-Request-ID", requestId)
.header("Accept", "application/json")
.headers(Map.of("X-App", "myapp", "X-Version", "1.0"))
.execute();
认证
// Bearer Token(OAuth2 / JWT)
Vostok.Http.get("https://api.example.com/me")
.bearer(accessToken)
.execute();
// HTTP Basic Auth
Vostok.Http.get("https://api.example.com/resource")
.basic("username", "password")
.execute();
// API Key(Header 方式)
Vostok.Http.get("https://api.example.com/data")
.apiKeyHeader("X-Api-Key", apiKey)
.execute();
// API Key(Query 参数方式)
Vostok.Http.get("https://api.example.com/data")
.apiKeyQuery("api_key", apiKey)
.execute();
请求体
// JSON 对象(自动序列化,Content-Type: application/json)
.bodyJson(object)
// 纯文本(Content-Type: text/plain; charset=UTF-8)
.bodyText("hello world")
// 原始字节(自定义 Content-Type)
.bodyBytes(bytes, "application/octet-stream")
// 仅修改 Content-Type,不改变已设置的 body
.contentType("application/xml; charset=UTF-8")
请求级超时与重试覆盖
// 覆盖全局超时配置(仅对本次请求生效)
Vostok.Http.post("https://slow-service.example.com/process")
.bodyJson(payload)
.timeoutMs(60000) // 总超时 60 秒(等价于 totalTimeoutMs)
.readTimeoutMs(30000) // 读取超时 30 秒
.retry(3) // 最多重试 3 次
.retryOnStatuses(503, 429)// 仅对这些状态码重试
.retryMethods("POST") // 允许 POST 重试(覆盖全局配置)
.retryOnNetworkError(true)
.retryOnTimeout(false)
.failOnNon2xx(false) // 本次不在非 2xx 时抛异常
.maxResponseBodyBytes(64 * 1024 * 1024) // 允许最大 64MB 响应
.execute();
VKHttpResponse 响应对象
VKHttpResponse res = Vostok.Http.get("https://api.example.com/users/1").execute();
// 状态码
int status = res.statusCode(); // 如 200
boolean ok = res.is2xx(); // true 表示 2xx
// 响应头
Map<String, List<String>> headers = res.headers();
// 响应体:文本
String text = res.bodyText(); // UTF-8 解码
String text = res.bodyText(Charset.forName("GBK")); // 指定编码
// 响应体:JSON 反序列化
User user = res.bodyJson(User.class);
// 响应体:原始字节
byte[] bytes = res.bodyBytes();
failOnNon2xx 说明
当全局或请求级 failOnNon2xx=true(默认)时,非 2xx 响应会抛出 VKHttpException,不会返回 VKHttpResponse。
设置 .failOnNon2xx(false) 可关闭此行为,自行检查 res.statusCode()。
命名 Client
命名 Client 绑定 baseUrl 和独立配置。使用相对路径时,运行时自动拼接 baseUrl。
注册命名 Client
Vostok.Http.registerClient("payments", new VKHttpClientConfig()
.baseUrl("https://payments.internal")
.connectTimeoutMs(2000)
.totalTimeoutMs(8000)
.maxRetries(3)
.putHeader("X-Api-Key", apiKey) // 此 Client 的默认请求头
.bearer(serviceToken) // 默认 Bearer Token 认证
);
Vostok.Http.registerClient("audit", new VKHttpClientConfig()
.baseUrl("https://audit.internal")
.circuitEnabled(true)
.circuitFailureRateThreshold(50)
.circuitOpenWaitMs(5000L)
);
使用命名 Client 发请求
// 方式一:withClient(Runnable) 切换上下文,所有相对路径请求使用该 Client
Vostok.Http.withClient("payments", () -> {
VKHttpResponse res = Vostok.Http.post("/charge")
.bodyJson(chargeRequest)
.execute();
processResult(res);
});
// 方式二:withClient(Supplier) 切换上下文并返回值
User user = Vostok.Http.withClient("payments", () ->
Vostok.Http.get("/account/info").executeJson(User.class)
);
// 方式三:通过请求构建器的 client() 指定,不依赖 withClient 上下文
VKHttpResponse res = Vostok.Http.request()
.client("payments")
.post("/refund")
.bodyJson(refundRequest)
.execute();
// 查看所有已注册的命名 Client
Set<String> names = Vostok.Http.clientNames();
// 获取当前线程上下文中激活的 Client 名(withClient 内返回名称,否则返回 null)
String current = Vostok.Http.currentClientName();
异步请求
// 异步 GET,返回 CompletableFuture<VKHttpResponse>
CompletableFuture<VKHttpResponse> future =
Vostok.Http.get("https://api.example.com/data").executeAsync();
future.thenAccept(res ->
Vostok.Log.info("got {} bytes", res.bodyBytes().length));
// 异步 POST 并解析 JSON
CompletableFuture<Order> futureOrder =
Vostok.Http.post("https://api.example.com/orders")
.bodyJson(orderRequest)
.executeJsonAsync(Order.class);
futureOrder.thenAccept(order -> Vostok.Log.info("created order {}", order.id()))
.exceptionally(ex -> { Vostok.Log.error("failed", ex); return null; });
流式响应
流式响应适合下载大文件或实时接收数据,不将全部响应体读入内存。
同步流式接收(executeStream)
// 同步阻塞,直到流结束
Vostok.Http.get("https://files.example.com/large.zip")
.executeStream(new VKHttpChunkListener() {
public void onOpen(VKHttpResponseMeta meta) {
System.out.println("status: " + meta.statusCode());
}
public void onChunk(byte[] chunk) {
outputStream.write(chunk, 0, chunk.length);
}
public void onError(Throwable t) {
Vostok.Log.error("stream error", t);
}
public void onComplete() {
outputStream.close();
}
});
异步流式接收(executeStreamAsync)
CompletableFuture<Void> streamFuture =
Vostok.Http.get("https://files.example.com/data.csv")
.executeStreamAsync(new VKHttpChunkListener() {
public void onChunk(byte[] chunk) { process(chunk); }
public void onComplete() { finalize(); }
});
streamFuture.join(); // 等待流结束
持久化流会话(openStream)
// 返回 Session 对象,可随时主动关闭
VKHttpStreamSession session = Vostok.Http.get("https://stream.example.com/feed")
.openStream(new VKHttpChunkListener() {
public void onChunk(byte[] chunk) { process(chunk); }
public void onComplete() {}
});
System.out.println(session.isOpen()); // true
// 主动关闭流
session.close();
// 或
session.cancel();
SSE(Server-Sent Events)
同步 SSE(executeSse)
// 同步阻塞,直到 SSE 流结束
Vostok.Http.get("https://api.example.com/events")
.header("Accept", "text/event-stream")
.executeSse(new VKHttpSseListener() {
public void onOpen(VKHttpResponseMeta meta) {
Vostok.Log.info("SSE connected, status={}", meta.statusCode());
}
public void onEvent(VKHttpSseEvent event) {
Vostok.Log.info("event={}, id={}, data={}",
event.getEvent(), event.getId(), event.getData());
}
public void onError(Throwable t) {
Vostok.Log.error("SSE error", t);
}
public void onComplete() {
Vostok.Log.info("SSE stream closed");
}
});
异步 SSE(executeSseAsync)
// 异步执行,返回 CompletableFuture<Void>,流结束时 complete
CompletableFuture<Void> sseFuture =
Vostok.Http.get("https://api.example.com/events")
.executeSseAsync(new VKHttpSseListener() {
public void onEvent(VKHttpSseEvent event) {
handleEvent(event.getData());
}
});
sseFuture.thenRun(() -> System.out.println("SSE done"));
持久化 SSE 会话(openSse)
// 返回 Session,可手动关闭(适合需要主动断开的场景)
VKHttpStreamSession session = Vostok.Http.get("https://api.example.com/events")
.openSse(new VKHttpSseListener() {
public void onEvent(VKHttpSseEvent event) {
if ("done".equals(event.getEvent())) {
session.close(); // 收到特定事件后关闭
}
}
});
// 稍后关闭
session.close();
VKHttpSseEvent 字段说明:
| 方法 | 类型 | 说明 |
|---|---|---|
getEvent() | String | 事件类型名(SSE event: 字段),无则为 null |
getId() | String | 事件 ID(SSE id: 字段),无则为 null |
getData() | String | 事件数据(SSE data: 字段,多行自动合并) |
getRetryMs() | Long | 服务端建议的重连延迟(SSE retry: 字段,ms),无则为 null |
getExtFields() | Map<String,String> | 扩展字段(非标准 SSE 字段),不可修改 |
WebSocket
// 建立 WebSocket 连接(阻塞直到连接建立或超时)
VKHttpWebSocketSession ws = Vostok.Http.request()
.get("wss://ws.example.com/chat")
.header("Authorization", "Bearer " + token)
.build()
.let(req -> Vostok.Http.websocket(req, new VKHttpWebSocketListener() {
public void onOpen(VKHttpWebSocketSession session) {
session.sendText("hello");
}
public void onMessage(VKHttpWebSocketSession session, String text) {
Vostok.Log.info("received: {}", text);
}
public void onBinary(VKHttpWebSocketSession session, byte[] data) {
processBinary(data);
}
public void onClose(VKHttpWebSocketSession session, int code, String reason) {
Vostok.Log.info("closed: {} {}", code, reason);
}
public void onError(VKHttpWebSocketSession session, Throwable err) {
Vostok.Log.error("ws error", err);
}
}));
// 通过 websocket(VKHttpRequest, listener) 建立连接
VKHttpRequest req = Vostok.Http.get("wss://ws.example.com/chat").build();
VKHttpWebSocketSession ws = Vostok.Http.websocket(req, listener);
// 发送消息
ws.sendText("ping"); // 异步发送文本
ws.sendBinary(data); // 异步发送二进制
ws.sendText("bye").thenRun(() -> ws.close()); // 发送后关闭
// 关闭连接
ws.close(); // 正常关闭(状态码 1000)
ws.close(1001, "going away"); // 指定状态码和原因
boolean open = ws.isOpen(); // 查询连接状态
拦截器
拦截器执行顺序:全局拦截器(按注册顺序)→ 客户端级拦截器(按注册顺序)→ 实际 HTTP 执行(含重试)。
// 全局拦截器——追加请求追踪 Header
Vostok.Http.addInterceptor(chain -> {
VKHttpRequest req = chain.request();
Vostok.Log.debug("→ {} {}", req.getMethod(), req.getUrlOrPath());
VKHttpResponse res = chain.proceed();
Vostok.Log.debug("← {}", res.statusCode());
return res;
});
// 修改请求(追加 Header 后透传)
Vostok.Http.addInterceptor(chain -> {
VKHttpRequest original = chain.request();
// 构建新请求:复制原请求,追加 Header
VKHttpRequest modified = Vostok.Http.request()
.client(original.getClientName())
.method(original.getMethod())
.url(original.getUrlOrPath())
.header("X-Trace-ID", UUID.randomUUID().toString())
.build();
return chain.proceed(modified);
});
// 针对特定命名 Client 的拦截器
Vostok.Http.addInterceptor("payments", chain -> {
Vostok.Log.debug("payments call: {}", chain.request().getUrlOrPath());
return chain.proceed();
});
// 在 VKHttpConfig / VKHttpClientConfig 中预置拦截器
Vostok.Http.init(new VKHttpConfig()
.addInterceptor(chain -> {
// 全局签名拦截器
return chain.proceed();
})
);
Vostok.Http.registerClient("billing", new VKHttpClientConfig()
.baseUrl("https://billing.internal")
.addInterceptor(chain -> chain.proceed()) // 客户端级拦截器
);
熔断器(Circuit Breaker)
// 全局启用熔断器
Vostok.Http.init(new VKHttpConfig()
.circuitEnabled(true)
.circuitWindowSize(20) // 滑动窗口请求数
.circuitMinCalls(10) // 触发熔断计算的最小请求数
.circuitFailureRateThreshold(50) // 失败率阈值(%),超过则熔断
.circuitOpenWaitMs(5000) // 熔断开启后等待 5s 再尝试半开
.circuitHalfOpenMaxCalls(3) // 半开状态最多允许 3 次请求探测
.circuitRecordStatuses(429, 500, 502, 503, 504) // 计为失败的状态码
);
// 或仅对特定命名 Client 启用
Vostok.Http.registerClient("risky", new VKHttpClientConfig()
.baseUrl("https://risky.internal")
.circuitEnabled(true)
.circuitFailureRateThreshold(60)
);
舱壁(Bulkhead)
// 全局舱壁:限制最大并发请求数
Vostok.Http.init(new VKHttpConfig()
.bulkheadEnabled(true)
.bulkheadMaxConcurrent(100) // 最大并发数
.bulkheadQueueSize(50) // 等待队列大小(0 = 无队列,满即拒绝)
.bulkheadAcquireTimeoutMs(2000) // 等待获取许可的超时时间(0 = 立即失败)
);
客户端限流
// 限制发出请求的速率
Vostok.Http.init(new VKHttpConfig()
.rateLimitQps(100) // 每秒最多 100 个请求
.rateLimitBurst(20) // 突发容量(令牌桶,0 = 与 QPS 相同)
);
TLS / mTLS(命名 Client)
Vostok.Http.registerClient("secure", new VKHttpClientConfig()
.baseUrl("https://secure.internal")
// 信任自签名证书(服务端证书验证)
.trustStore("/etc/certs/server.p12", "trustpass") // 默认 PKCS12
.trustStore("/etc/certs/server.jks", "trustpass", "JKS") // 指定格式
// mTLS:客户端证书
.keyStore("/etc/certs/client.p12", "keystorepass")
.keyStore("/etc/certs/client.p12", "keystorepass", "keypass", "PKCS12")
);
Cookie 管理
// 全局启用 Cookie(自动接受所有 Set-Cookie)
Vostok.Http.init(new VKHttpConfig()
.cookiePolicy("ACCEPT_ALL")
// 可选值:ACCEPT_ALL / ACCEPT_NONE / ACCEPT_ORIGINAL_SERVER
);
// 仅对特定命名 Client 启用
Vostok.Http.registerClient("web", new VKHttpClientConfig()
.baseUrl("https://webapp.example.com")
.cookiePolicy("ACCEPT_ORIGINAL_SERVER")
);
指标统计
// 全局指标快照
VKHttpMetrics m = Vostok.Http.metrics();
System.out.printf(
"total=%d, success=%d, failed=%d, retried=%d, timeout=%d, netErr=%d%n",
m.totalCalls(), m.successCalls(), m.failedCalls(),
m.retriedCalls(), m.timeoutCalls(), m.networkErrorCalls());
System.out.printf(
"streamOpens=%d, sseEvents=%d, totalCostMs=%d%n",
m.streamOpens(), m.sseEvents(), m.totalCostMs());
// 按状态码分布
m.statusCounts().forEach((status, count) ->
System.out.println(status + ": " + count));
// 特定命名 Client 的独立指标
VKHttpMetrics pm = Vostok.Http.metrics("payments");
// 重置全局指标(慎用,会清零所有计数)
Vostok.Http.resetMetrics();
VKHttpMetrics 字段说明:
| 字段方法 | 类型 | 说明 |
|---|---|---|
totalCalls() | long | 总请求次数(含重试) |
successCalls() | long | 成功请求次数(2xx) |
failedCalls() | long | 最终失败的请求次数 |
retriedCalls() | long | 触发过重试的请求次数 |
timeoutCalls() | long | 超时次数 |
networkErrorCalls() | long | 网络错误次数(连接失败等) |
streamOpens() | long | 流/SSE 连接建立次数 |
streamCloses() | long | 流/SSE 正常关闭次数 |
streamErrors() | long | 流/SSE 出错次数 |
sseEvents() | long | 接收到的 SSE 事件总数 |
totalCostMs() | long | 所有请求累计耗时(ms) |
statusCounts() | Map<Integer,Long> | 按 HTTP 状态码统计的响应次数 |
生命周期
// 检查是否已初始化
boolean running = Vostok.Http.started();
// 获取当前配置快照(返回副本)
VKHttpConfig cfg = Vostok.Http.config();
// 重新初始化(替换全局配置,不影响已注册的命名 Client)
Vostok.Http.reinit(new VKHttpConfig().totalTimeoutMs(5000));
// 关闭 HTTP 模块(释放连接池资源)
Vostok.Http.close();
工具方法
// URL 编码(对查询参数值或路径段进行 percent encoding)
String encoded = Vostok.Http.urlEncode("hello world & more");
// → "hello+world+%26+more"
VKHttpConfig 配置参数
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| 基础 | |||
| connectTimeoutMs | long | 3000 | TCP 连接超时(ms,最小 1) |
| totalTimeoutMs / requestTimeoutMs | long | 10000 | 请求总超时(ms,含重试),两者等价 |
| readTimeoutMs | long | 0 | 读取超时(ms,0 = 不限制) |
| followRedirects | boolean | true | 是否自动跟随重定向 |
| failOnNon2xx | boolean | true | 非 2xx 状态码时抛 VKHttpException |
| maxResponseBodyBytes | long | 8 MB | 响应体最大字节数(超出时抛异常) |
| userAgent | String | "VostokHttp/1.0" | User-Agent 请求头 |
| defaultHeaders / putHeader | Map / String,String | 空 | 所有请求的默认 Header;putHeader 单个添加 |
| cookiePolicy | String | null(不启用) | Cookie 策略:ACCEPT_ALL / ACCEPT_NONE / ACCEPT_ORIGINAL_SERVER |
| logEnabled | boolean | true | 是否开启内置请求日志 |
| metricsEnabled | boolean | true | 是否收集请求指标 |
| clientReuseIdleEvictMs | long | 600000 | 底层 HttpClient 空闲驱逐时间(ms) |
| 重试 | |||
| maxRetries | int | 1 | 最大重试次数(0 = 不重试) |
| retryBackoffBaseMs | long | 100 | 指数退避基础时间(ms) |
| retryBackoffMaxMs | long | 1000 | 指数退避单次最大时间(ms) |
| maxRetryDelayMs | long | 30000 | 所有重试累计等待上限(ms) |
| retryJitterEnabled | boolean | true | 退避时间加随机抖动,避免惊群效应 |
| retryOnNetworkError | boolean | true | 网络异常时是否重试 |
| retryOnTimeout | boolean | true | 超时时是否重试 |
| respectRetryAfter | boolean | true | 遵守响应头 Retry-After 的等待时间 |
| retryOnStatuses | Set<Integer> | {429,502,503,504} | 触发重试的 HTTP 状态码集合 |
| retryMethods | Set<String> | {GET,HEAD,OPTIONS,PUT,DELETE} | 允许重试的 HTTP 方法 |
| requireIdempotencyKeyForUnsafeRetry | boolean | true | POST/PATCH 等非安全方法重试时要求 Idempotency-Key Header |
| idempotencyKeyHeader | String | "Idempotency-Key" | 幂等键 Header 名称 |
| 熔断器 | |||
| circuitEnabled | boolean | false | 是否启用熔断器 |
| circuitWindowSize | int | 20 | 滑动窗口请求数 |
| circuitMinCalls | int | 10 | 触发熔断计算的最小请求数 |
| circuitFailureRateThreshold | int | 50 | 失败率阈值(%),超过则熔断 |
| circuitOpenWaitMs | long | 5000 | 熔断开启后等待恢复的时间(ms) |
| circuitHalfOpenMaxCalls | int | 3 | 半开状态最多允许的探测请求数 |
| circuitRecordStatuses | Set<Integer> | {429,500,502,503,504} | 计入失败统计的 HTTP 状态码 |
| 舱壁 | |||
| bulkheadEnabled | boolean | false | 是否启用并发舱壁限制 |
| bulkheadMaxConcurrent | int | 100 | 最大并发请求数 |
| bulkheadQueueSize | int | 0 | 等待队列大小(0 = 无队列,满即拒绝) |
| bulkheadAcquireTimeoutMs | long | 0 | 等待获取并发许可的超时(0 = 立即失败) |
| 限流 | |||
| rateLimitQps | int | 0(不限流) | 每秒最大请求数(令牌桶) |
| rateLimitBurst | int | 0 | 突发容量(0 = 与 QPS 相同) |
| 流 / SSE | |||
| streamEnabled | boolean | true | 是否启用流式响应支持 |
| streamIdleTimeoutMs | long | 60000 | 流连接空闲超时(ms,0 = 不限制) |
| streamTotalTimeoutMs | long | 0 | 流连接总时长上限(ms,0 = 不限制) |
| streamExecutorThreads | int | 4 | 流处理线程池线程数 |
| streamQueueCapacity | int | 1024 | 流任务队列容量 |
| sseMaxEventBytes | int | 1 MB | 单个 SSE 事件最大字节数 |
| sseEmitDoneEvent | boolean | false | 流结束时是否触发一个合成的 "done" 事件 |
VKHttpClientConfig 命名 Client 配置
命名 Client 配置中,数值型字段默认为 -1(表示继承全局配置);Boolean 字段默认为 null(同样继承全局)。仅显式设置的字段会覆盖全局配置。
| 参数 | 说明 |
|---|---|
| baseUrl | 基础 URL,与相对路径拼接 |
| connectTimeoutMs / totalTimeoutMs / readTimeoutMs | 超时配置,覆盖全局(≤0 时继承全局) |
| maxRetries | 最大重试次数(-1 继承全局) |
| maxResponseBodyBytes | 响应体上限(≤0 继承全局) |
| putHeader(name, value) | 添加此 Client 的默认请求头(叠加到全局 defaultHeaders 之上) |
| bearer(token) / basic(user, pass) | 快捷设置认证(等价于 .auth(new VKBearerAuth(...))) |
| auth(VKHttpAuth) | 自定义认证实现 |
| retryOnStatuses / retryMethods | 覆盖全局重试状态码和方法 |
| circuitEnabled / bulkheadEnabled / rateLimitQps | 覆盖全局弹性配置(null 继承全局) |
| trustStore(path, password [, type]) | TLS 信任库(验证服务端证书) |
| keyStore(path, storePassword [, keyPassword, type]) | mTLS 客户端证书 |
| sslContext(SSLContext) | 直接提供自定义 SSLContext |
| addInterceptor(VKHttpInterceptor) | 添加客户端级拦截器(在全局拦截器之后执行) |
| cookiePolicy | Cookie 策略(null 继承全局) |
API 速查
生命周期
| 方法 | 返回值 | 说明 |
|---|---|---|
init() | void | 以默认配置显式初始化(已初始化时幂等) |
init(VKHttpConfig) | void | 以自定义配置初始化(已初始化时幂等) |
reinit(VKHttpConfig) | void | 重新初始化,替换全局配置 |
started() | boolean | 是否已初始化 |
config() | VKHttpConfig | 当前全局配置的副本快照 |
close() | void | 关闭模块,释放连接池 |
请求构建(VKHttpRequestBuilder)
| 方法 | 说明 |
|---|---|
get(url) / post(url) / put(url) / patch(url) / delete(url) / head(url) / options(url) | 设置方法和 URL |
client(name) | 指定命名 Client |
path(name, value) | 路径参数替换({name} → value) |
query(name, value) / query(name, List) | 添加查询参数(支持多值) |
header(name, value) / headers(Map) | 请求头 |
bearer(token) / basic(user, pass) / apiKeyHeader(n,v) / apiKeyQuery(n,v) / auth(VKHttpAuth) | 认证 |
bodyJson(obj) / bodyText(str) / bodyBytes(bytes, ct) / contentType(ct) | 请求体 |
form(name, value) / form(Map) | 表单字段(application/x-www-form-urlencoded) |
multipart(name, value) / multipart(name, filename, contentType, bytes) | Multipart 文件上传 |
timeoutMs(ms) / totalTimeoutMs(ms) / readTimeoutMs(ms) | 请求级超时覆盖 |
retry(n) / retryOnStatuses(...) / retryMethods(...) / retryOnNetworkError(b) / retryOnTimeout(b) | 请求级重试覆盖 |
failOnNon2xx(b) / maxResponseBodyBytes(n) | 请求级行为覆盖 |
build() | 构建 VKHttpRequest 对象 |
执行方法(VKHttpRequestBuilder / VostokHttp)
| 方法 | 返回值 | 说明 |
|---|---|---|
execute() | VKHttpResponse | 同步执行请求 |
executeJson(Class) | T | 同步执行并反序列化 JSON 响应体 |
executeAsync() | CompletableFuture<VKHttpResponse> | 异步执行 |
executeJsonAsync(Class) | CompletableFuture<T> | 异步执行并反序列化 JSON |
executeStream(VKHttpChunkListener) | void | 同步流式接收,阻塞至完成 |
executeStreamAsync(VKHttpChunkListener) | CompletableFuture<Void> | 异步流式接收 |
openStream(VKHttpChunkListener) | VKHttpStreamSession | 建立流会话,返回可关闭的 Session |
executeSse(VKHttpSseListener) | void | 同步 SSE,阻塞至流结束 |
executeSseAsync(VKHttpSseListener) | CompletableFuture<Void> | 异步 SSE,流结束时 complete |
openSse(VKHttpSseListener) | VKHttpStreamSession | 建立持久 SSE 会话,返回可关闭的 Session |
websocket(VKHttpRequest, VKHttpWebSocketListener) | VKHttpWebSocketSession | 建立 WebSocket 连接(通过门面调用) |
命名 Client 管理
| 方法 | 返回值 | 说明 |
|---|---|---|
registerClient(name, VKHttpClientConfig) | void | 注册命名 Client |
withClient(name, Runnable) | void | 在命名 Client 上下文中执行操作 |
withClient(name, Supplier<T>) | T | 在命名 Client 上下文中执行并返回结果 |
clientNames() | Set<String> | 已注册的所有命名 Client 名称集合 |
currentClientName() | String | 当前线程激活的 Client 名(withClient 内有效,否则返回 null) |
拦截器与指标
| 方法 | 说明 |
|---|---|
addInterceptor(VKHttpInterceptor) | 添加全局拦截器(对所有 Client 生效) |
addInterceptor(name, VKHttpInterceptor) | 添加命名 Client 级拦截器 |
metrics() | 获取全局请求指标快照 |
metrics(clientName) | 获取指定命名 Client 的指标快照 |
resetMetrics() | 重置全局指标计数 |
urlEncode(value) | 对字符串进行 URL percent 编码 |