Java 26 终于原生支持 HTTP/3 了:告别 Netty,直接用 QUIC

欢迎关注微信公众号:FSA全栈行动 👋

一、痛点

以前在 Java 环境里想要搞定 HTTP/3 或者 QUIC 协议,简直是件挺折腾的事。

如果你想在 Java 应用中使用这些现代协议,你基本上没法直接用标准库。为了能处理好 UDP 套接字,你不得不引入像 NettyVert.x 这样非常"重"的第三方库。这对于只想做一个简单的 HTTP 请求,却不想引入一堆复杂依赖的开发者来说,确实是个负担。

而且,除了依赖问题,还有一个技术硬伤:TCP 的队头阻塞(Head-of-Line Blocking)。

HTTP/2 虽然比 HTTP/1.1 强很多,支持了多路复用,但因为它底层跑的还是 TCPTCP 要求包必须按顺序到达,这就导致一旦在传输过程中丢了一个包,整个 TCP 连接都会卡住,必须等那个丢掉的包重传成功后,后面的所有请求才能继续。在移动网络或者高延迟场景下,这种表现简直是灾梦。

为了对比,我整理了一个简单的逻辑对比:

特性 HTTP/2 HTTP/3
底层传输 TCP QUIC (UDP)
丢包表现 整个连接卡死(队头阻塞) 仅丢包的 stream 受影响,其他不受干扰
适用场景 稳定、低延迟网络 移动网络、高丢包环境

二、实现:原生支持 HTTP/3

随着 Java 26 的正式发布,JEP 517 终于落地了。这意味着 Java 的标准 HttpClient 现在可以直接支持 HTTP/3 了,再也不用为了 QUIC 去硬啃 Netty 了。

1、如何开启 HTTP/3

因为 HTTP/3 基于 UDP 运行,目前还没法像 TCP 那样在全世界所有防火墙和代理上都跑得通,所以 Java 26 并没有默认开启它,默认还是 HTTP/2

如果你想用 QUIC,需要显式地在 HttpClient 或者请求构建器里指定版本:

Java 复制代码
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class NativeQuicClient {
    public static void main(String[] args) throws Exception {
        // 在客户端级别显式设置 HTTP/3
        HttpClient client = HttpClient.newBuilder()
                .version(HttpClient.Version.HTTP_3)
                .build();

        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create("https://openjdk.org/"))
                .GET()
                .build();

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

        // 输出实际使用的协议版本
        System.out.println("Protocol used: " + response.version());
    }
}

2、Fallback 机制与 Alt-Svc

这里有个细节处理得挺聪明。

如果你配置了 HTTP/3JVM 会尝试建立 UDP 连接。但如果服务器不支持,或者中间的防火墙把 UDP 给拦了,HttpClient 会自动"降级"回 HTTP/2HTTP/1.1

而且,Java 26 能够原生解析 Alt-Svc(Alternative Service)响应头。简单来说,当服务器通过 HTTP/2 响应并告知"我其实支持 HTTP/3"时,JVM 会自动在后续请求中切换到 QUIC 协议。这种平滑切换的体验非常好。

三、进阶:强制开启模式

在做微服务架构时,如果你的服务是在可控的内网环境下运行,你可能并不想要那种"先尝试 UDP 失败再降级到 TCP"的检测开销。

这时候你可以通过 Http3DiscoveryMode 来强制要求只使用 HTTP/3。如果 QUIC 连接失败,直接报错,不再尝试 fallback。

Java 复制代码
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpOption;
import java.net.http.Http3DiscoveryMode;

public class StrictQuicClient {
    public static void main(String[] args) throws Exception {
        HttpClient client = HttpClient.newBuilder()
                .version(HttpClient.Version.HTTP_3)
                .build();

        HttpRequest strictRequest = HttpRequest.newBuilder()
                .uri(URI.create("https://internal-api.enterprise.local/"))
                // 开启严格模式:如果 UDP/QUIC 不可用,请求直接失败,不进行 fallback
                .setOption(HttpOption.H3_DISCOVERY, Http3DiscoveryMode.HTTP_3_URI_ONLY)
                .GET()
                .build();

        client.send(strictRequest, HttpResponse.BodyHandlers.ofString());
    }
}

四、最后

JEP 517 的引入,确实让 Java 的网络能力迈进了一大步。

总结一下这次更新带来的收益:

  • 不再需要重型依赖 :不用为了用个 QUIC 就背着一个 Netty 跑。

  • 配置简单 :通过 HttpClient.Version.HTTP_3 就能搞定。

  • 智能化 :自动处理 Alt-SvcTCP 回退。

配合上 Virtual Threads 的高并发能力,现在的 java.net.http 模块在处理高性能网络通信时,表现真的很硬核。

如果文章对您有所帮助, 请不吝点击关注一下我的微信公众号:FSA全栈行动, 这将是对我最大的激励. 公众号不仅有Android技术, 还有iOS, Python等文章, 可能有你想要了解的技能知识点哦~

相关推荐
用户40966601317511 小时前
Jackson 序列化:@JsonIgnore / @JsonProperty / @JsonFormat / @JsonInclude / @JsonUnwrapped 一次讲清楚
java·后端
码路漫漫1 小时前
用了 Caffeine,消息为什么还是被处理了两次?
java
云和数据.ChenGuang1 小时前
fastapi项目拆分实战数据模型
java·服务器·数据库·人工智能·深度学习·fastapi·强化学习
小龙报2 小时前
【优选算法】1.搜索插入位置 2.x的平方根
java·c语言·数据结构·c++·python·算法·蓝桥杯
山荷枝2 小时前
04-框架--SpringBoot
java·spring boot·后端
linux修理工2 小时前
内存占用 99% 且 Java 程序较多的优化建议
java·开发语言
weixin_460443562 小时前
企业考试系统如何对接OA、钉钉和企业微信?SSO单点登录、组织同步与权限一致性设计
java·开发语言·数据库
Sylvia33.2 小时前
篮球数据API的技术架构与工程实践:基于火星数据WebSocket实时推送体系
java·python·websocket·网络协议·架构
Hi李耶3 小时前
【LeetCode】15.三数之和
java·算法·leetcode