今天分享 JDK 26 的 HTTP/3 Client API。重点不是“协议更新了”,而是 Java 后端和 Agent 系统的出站访问开始有了标准 HTTP/3 路径。我们会看 JDK HttpClient 怎么 opt-in,Spring Boot RestClient 怎么接,以及为什么安全、回退和观测比协议本身更关键。

分享日期:2026-06-15
主题:Java / JDK 26 / HTTP/3 / Java HttpClient / Spring Boot RestClient / Spring Cloud / Agent 出站治理

1. 为什么今天值得关注

JDK 26 的特性列表里包含 JEP 517:HTTP/3 for the HTTP Client API。JEP 状态是 Delivered,目标 release 是 26。它把 Java 11 引入的标准 java.net.http.HttpClient 继续往前推了一步:客户端可以显式选择 HTTP/3,和支持 HTTP/3 的服务端通信。

这不是一个“所有接口立刻变快”的开关。JEP 517 说得很清楚:HTTP/3 不会成为默认协议,开发者需要主动 opt-in;如果目标服务不支持 HTTP/3,默认行为可以退回到 HTTP/2 或 HTTP/1.1。

对 Java 后端团队来说,真正值得关注的是出站调用治理:

  • Spring Boot 的 RestClient、HTTP Service Interface、工具服务、Webhook、RAG 文档抓取、模型供应商 API,底层都可能走 HTTP client。
  • AI Agent 和 MCP 工具调用会显著增加“应用主动访问外部系统”的比例。
  • HTTP/3 基于 QUIC 和 UDP,在高延迟、连接迁移、弱网和丢包场景有潜在价值。
  • 但 HTTP/3 也会碰到企业防火墙、代理、服务网格、可观测性、SSRF 防护和回退策略的问题。

一句话:JDK 26 的 HTTP/3 不是让所有 Java 服务都改协议,而是让 Java 应用在“出站访问外部服务”时多了一个标准、可治理的协议选项。

2. HTTP/3 在 JDK 26 里改了什么

JEP 517 的核心变化可以压缩成五点:

  • HttpClient 和 HttpRequest 可以设置首选协议版本为 HttpClient.Version.HTTP_3
  • HTTP/3 是显式选择,不替换当前默认行为。
  • 如果目标服务不支持 HTTP/3,默认可以退回 HTTP/2 或 HTTP/1.1。
  • JDK 只提供客户端能力,不提供 HTTP/3 服务端实现。
  • JDK 不把 QUIC 暴露成独立通用 API,也不更新旧的 java.net.URL 协议处理器。

最小代码示例:

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;

public class Http3Example {

    public String fetch(String url) throws Exception {
        HttpClient client = HttpClient.newBuilder()
                .version(HttpClient.Version.HTTP_3)
                .connectTimeout(Duration.ofSeconds(2))
                .followRedirects(HttpClient.Redirect.NEVER)
                .build();

        HttpRequest request = HttpRequest.newBuilder(URI.create(url))
                .timeout(Duration.ofSeconds(5))
                .GET()
                .build();

        HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());

        System.out.printf("status=%s version=%s%n", response.statusCode(), response.version());
        return response.body();
    }
}

也可以只对单个请求设置:

HttpRequest request = HttpRequest.newBuilder(URI.create("https://api.example.com/data"))
        .version(HttpClient.Version.HTTP_3)
        .timeout(Duration.ofSeconds(5))
        .GET()
        .build();

工程上更建议按“目标服务”建 client,而不是每个请求临时切版本。比如模型供应商 API、文档抓取 API、Webhook API 各自有不同的超时、重试、协议偏好和安全策略。

3. 别把 HTTP/3 当默认加速器

HTTP/3 的价值主要来自 QUIC:

  • 基于 UDP,而不是 TCP。
  • 默认使用 TLS 1.3。
  • 避免 HTTP/2 在 TCP 上遇到的队头阻塞问题。
  • 弱网、移动网络、高延迟链路上更可能有收益。
  • 连接建立和迁移能力更适合跨网络切换。

但这些收益有前提:

  • 目标服务端要支持 HTTP/3。
  • 出站网络要允许 UDP/443。
  • 企业代理、WAF、服务网格、透明网关要能处理或放行。
  • 客户端指标要能区分 HTTP/3、HTTP/2、HTTP/1.1。
  • 回退行为要被监控,否则你以为在跑 HTTP/3,实际一直在回退。

因此,HTTP/3 的正确姿势不是“全局打开”,而是给少数高价值出站目标做灰度:

  • 模型供应商 API。
  • 多区域对象存储或文档下载。
  • 外部 SaaS API。
  • Webhook 回调。
  • 面向公网的 RAG 页面抓取。

内网微服务之间,如果已经有成熟的服务网格、mTLS、gRPC、Gateway 和链路追踪,不需要为了追新协议强行切换。

4. Spring Boot RestClient 怎么接

Spring Framework 的 JdkClientHttpRequestFactory 可以基于 Java HttpClient 创建 ClientHttpRequestFactory。这意味着 Spring 的 RestClient 可以复用 JDK 26 的 HTTP/3 HttpClient

示例:

import java.net.http.HttpClient;
import java.time.Duration;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.JdkClientHttpRequestFactory;
import org.springframework.web.client.RestClient;

@Configuration(proxyBeanMethods = false)
public class Http3RestClientConfiguration {

    @Bean
    RestClient modelProviderRestClient(RestClient.Builder builder) {
        HttpClient httpClient = HttpClient.newBuilder()
                .version(HttpClient.Version.HTTP_3)
                .connectTimeout(Duration.ofSeconds(2))
                .followRedirects(HttpClient.Redirect.NEVER)
                .build();

        JdkClientHttpRequestFactory requestFactory = new JdkClientHttpRequestFactory(httpClient);
        requestFactory.setReadTimeout(Duration.ofSeconds(10));

        return builder
                .baseUrl("https://api.model-provider.example")
                .requestFactory(requestFactory)
                .build();
    }
}

调用侧保持普通 RestClient 风格:

ModelResponse response = modelProviderRestClient.post()
        .uri("/v1/responses")
        .body(request)
        .retrieve()
        .body(ModelResponse.class);

这类代码的重点不是“写法很新”,而是:协议偏好被绑定到一个明确的 client bean 上。这样可以分别给模型供应商、文档抓取、Webhook、内部 API 配置不同策略,避免一个全局 HTTP 客户端承担所有流量。

5. SSRF 防护不能因为 HTTP/3 放松

Spring Boot 4.1 的 REST client 文档已经提供 InetAddressFilter,可以限制 HTTP client 允许访问的远端地址,用于 SSRF 防护。对 Agent、Webhook、URL 抓取这类开放式出站调用,这个能力比协议版本更重要。

示例:

import org.springframework.boot.http.client.ClientHttpRequestFactoryBuilder;
import org.springframework.boot.http.client.HttpClientSettings;
import org.springframework.boot.http.client.InetAddressFilter;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.web.client.RestClient;

public class SafeOutboundClientFactory {

    public RestClient externalRestClient() {
        InetAddressFilter onlyExternalAddresses = InetAddressFilter.externalAddresses();

        HttpClientSettings settings = HttpClientSettings.defaults()
                .withInetAddressFilter(onlyExternalAddresses);

        ClientHttpRequestFactory requestFactory =
                ClientHttpRequestFactoryBuilder.jdk().build(settings);

        return RestClient.builder()
                .requestFactory(requestFactory)
                .build();
    }
}

如果某个场景要强制使用自定义 JDK HttpClient 来偏好 HTTP/3,也不要绕开安全边界。至少要补齐:

  • 只允许访问明确 allowlist 域名。
  • DNS 解析后仍要校验 IP 范围,防 DNS rebinding。
  • 禁止或严格控制重定向。
  • 禁止访问内网、localhost、链路本地地址、云元数据地址。
  • 请求大小、响应大小、超时、重试次数全部有限制。

HTTP/3 解决的是传输协议能力,不解决“应用能不能访问这个地址”的安全问题。

6. 对 Agent 和 MCP 的实际意义

Agent 应用里,出站调用比传统业务服务更复杂:

  • 模型供应商 API。
  • 向量库或检索服务。
  • MCP Server。
  • 内部工具服务。
  • 外部文档抓取。
  • Webhook、SaaS、工单、CRM、知识库。

其中有些目标在公网,有些在内网;有些可以用 HTTP/3,有些只能用 HTTP/1.1;有些需要强认证,有些来自用户配置;有些是只读,有些会触发业务写入。

推荐把 Agent 出站调用分成四类:

类型 示例 协议策略 安全策略
受控模型 API 模型供应商、Embedding API 可灰度 HTTP/3 固定域名、密钥、限流
受控内部工具 MCP Server、工单、订单 内网协议优先稳定 服务身份、RBAC、审计
受控外部 SaaS CRM、邮件、支付查询 按供应商能力评估 allowlist、超时、重试
开放 URL 抓取 用户输入链接、网页总结 不优先追 HTTP/3 SSRF、内容大小、沙箱

对开放 URL 抓取,HTTP/3 不是第一优先级。第一优先级是安全:

  • 先校验 URL scheme,只允许 https
  • DNS 解析后过滤 IP。
  • 禁止跳转到不允许的网段。
  • 设置下载大小上限。
  • 只提取纯文本或安全 HTML。
  • 给每个请求打 request id 和用户上下文。

对模型供应商 API,HTTP/3 更值得试点,因为目标域名固定、认证固定、流量大、跨公网,具备观测和灰度条件。

7. Spring Cloud 架构里的位置

HTTP/3 在微服务架构里应放在出站治理层,而不是替代所有东西。

flowchart LR
    User[用户 / 前端] --> Gateway[Spring Cloud Gateway]
    Gateway --> App[Spring Boot API]
    App --> Internal[内部服务 HTTP/gRPC]
    App --> Agent[Agent Service]
    Agent --> ModelClient[模型 API RestClient]
    Agent --> FetchClient[文档抓取 RestClient]
    Agent --> McpClient[MCP Client]
    ModelClient --> H3[HTTP/3 优先 / 可回退]
    FetchClient --> Safe[SSRF Filter / Size Limit]
    McpClient --> Mesh[内网治理 / RBAC / Audit]
    App --> OTel[OpenTelemetry / Micrometer]
    Agent --> OTel

建议:

  • Gateway 仍然负责入口认证、限流、请求大小和审计。
  • 内部服务调用优先保持团队已验证的 HTTP/2、gRPC、服务发现或服务网格模式。
  • 外部出站调用按目标服务建独立 client。
  • Spring Cloud Config 管协议偏好、灰度比例、超时、重试和 allowlist。
  • Vault 管模型 API key、Webhook secret、MCP 凭证。
  • CircuitBreaker 管模型供应商和外部 SaaS 降级。
  • Observability 必须记录实际协议版本,不要只记录目标 URL。

8. 配置化建议

把协议选择做成配置,不要写死在业务代码里:

outbound:
  clients:
    model-provider:
      base-url: https://api.model-provider.example
      preferred-protocol: HTTP_3
      connect-timeout: 2s
      read-timeout: 10s
      redirects: never
      allowed-hosts:
        - api.model-provider.example
    public-fetch:
      preferred-protocol: HTTP_2
      connect-timeout: 2s
      read-timeout: 5s
      max-response-size: 2MB
      allow-private-addresses: false

灰度策略:

  • 第一周只打开一个模型供应商 API。
  • 只在一个区域或一组实例启用。
  • 记录 response.version(),确认实际是否命中 HTTP/3。
  • 对比 P50、P95、P99、错误率、超时率、回退率。
  • 如果 UDP/443 被拦截导致延迟升高,马上回退 HTTP/2。

9. 可观测性要补哪些字段

建议在出站调用 span 或日志里增加:

{
  "clientName": "model-provider",
  "targetHost": "api.model-provider.example",
  "preferredProtocol": "HTTP_3",
  "actualProtocol": "HTTP_3",
  "fallback": false,
  "status": 200,
  "durationMs": 184,
  "tenantId": "t001",
  "scenario": "support-agent",
  "requestId": "req-20260615-001"
}

关键看四个指标:

  • HTTP/3 实际命中率。
  • HTTP/3 到 HTTP/2/HTTP/1.1 的回退率。
  • 按协议版本拆分的延迟和错误率。
  • UDP/443 网络失败和 TLS/QUIC 相关异常。

不要只看总体平均延迟。HTTP/3 的收益常常体现在高延迟、弱网、跨区域链路和尾延迟上。

10. 落地检查清单

第一步,确认环境:

  • 构建和运行环境是否已经有 JDK 26。
  • 目标 API 是否支持 HTTP/3。
  • 出站网络是否允许 UDP/443。
  • 企业代理、WAF、服务网格是否会拦截或降级。

第二步,改造 client:

  • 为目标服务建立独立 RestClient 或 HTTP Service client。
  • 显式设置 HttpClient.Version.HTTP_3
  • 设置 connect timeout、read timeout、redirect policy。
  • 记录 response.version()

第三步,补安全:

  • 对开放式 URL 场景启用 SSRF 防护。
  • 目标域名 allowlist。
  • DNS 解析后校验 IP。
  • 响应体大小限制。
  • 禁止跨域名重定向或对重定向重新校验。

第四步,灰度验证:

  • 小流量启用。
  • 和 HTTP/2 对照。
  • 监控错误率、超时率、回退率。
  • 保留配置开关,能分钟级回退。

第五步,纳入平台:

  • Spring Cloud Config 管协议偏好。
  • Vault 管凭证。
  • CircuitBreaker 管降级。
  • OpenTelemetry 管链路。
  • 审计日志记录 Agent 场景和工具调用上下文。

11. 常见坑

  • 以为 HTTP/3 会自动启用:JEP 517 明确是 opt-in,不会默认替换 HTTP/2。
  • 只看客户端代码,不看网络路径:UDP/443、代理、WAF、服务网格都会影响结果。
  • 忽略回退:实际可能一直在 HTTP/2,却以为 HTTP/3 生效。
  • 对内网服务强推 HTTP/3:内网稳定性、观测和安全体系通常比协议新旧更重要。
  • 用 HTTP/3 掩盖出站安全问题:SSRF、重定向、DNS rebinding、响应体大小仍然要防。
  • 把 Agent 工具调用全塞一个 RestClient:模型 API、MCP、Webhook、URL 抓取的风险不同,必须分 client 治理。
  • 只压测平均延迟:要看 P95/P99、回退率、弱网和跨区域链路。

12. 适合分享时强调的判断

JDK 26 的 HTTP/3 Client API 代表 Java 标准库正在补齐现代互联网出站访问能力。它不负责替代网关、服务网格、gRPC 或安全策略;它负责让 Java 应用在访问支持 HTTP/3 的目标服务时,有一个标准 API 可以试点和治理。

对 Spring Boot 和 Agent 团队,今天最务实的动作不是全量切 HTTP/3,而是选一个固定域名、高流量、跨公网的外部 API,建一个独立 RestClient,开启 HTTP/3 偏好,补齐 SSRF、超时、回退、观测和配置开关。先把出站调用的治理模型跑通,再谈协议升级收益。

13. 分享金句

HTTP/3 进入 JDK 26,不是让 Java 服务一夜之间换协议,而是让出站调用多了一个标准化选项。真正成熟的升级,不是把 HTTP_3 写进代码,而是把协议偏好、回退、安全边界和观测数据一起纳入工程控制面。

资料来源

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐