dotnet团队官方博客发布了一篇HTTP3的文章:HTTP/3 support in .NET 6:https://devblogs.microsoft.com/dotnet/http-3-support-in-dotnet-6/。文章介绍了.NET 6 将预览支持HTTP3,.NET 7正式支持HTTP3,原因主要是HTTP/3 的 RFC 尚未最终确定,因此仍然可以更改,并且在 .NET 6 中,HTTP/3 可能存在行为或性能问题。将 HTTP/3 包含在 .NET 6 中,可以开始尝试它。
HTTP/3 是 HTTP 的第三个即将发布的主要版本。HTTP/3 使用与 HTTP/1.1 和 HTTP/2 相同的语义:相同的请求方法、状态代码和消息字段适用于所有版本。差异在于基础传输。HTTP/1.1 和 HTTP/2 都将 TCP 用作其传输协议。HTTP/3 使用的是与 HTTP/3 同时开发的一种新传输技术,称为 QUIC。
与 HTTP/1.1 和 HTTP/2 相比,HTTP/3 和 QUIC 具有很多优势:
第一个请求的响应时间更短。QUIC 和 HTTP/3 在客户端和服务器之间以较少的往返次数协商连接。第一个请求更快地到达服务器,QUIC 使用 UDP 并内置 TLS,因此,当 TLS 握手作为连接的一部分发生时,建立连接会更快。
改进了发生连接数据包丢失时的体验。HTTP/2 通过一个 TCP 连接多路复用多个请求。如果在连接时发生数据包丢失,会影响所有请求。这个问题称为“队头阻塞”。由于 QUIC 提供本机多路复用,因此丢失的数据包只会影响已丢失数据的请求,因此在数据包丢失的情况下,它不再具有队头阻塞。
支持在网络之间转换。此功能对于移动设备非常有用,因为在移动设备更改位置时,在 WIFI 和移动电话网络之间切换是很常见的。目前,在切换网络时,HTTP/1.1 和 HTTP/2 连接会失败并提示错误。应用或 Web 浏览器必须重试任何失败的 HTTP 请求。HTTP/3 让应用或 Web 浏览器在网络发生更改时可以无缝地继续。不过 Kestrel 并不支持 .NET 6 中的网络转换。它可能在未来版本中可用。
.NET的QUIC 支持
QUIC被设计为 HTTP/3 的基础传输层,但它也可用于其他协议。它设计为适用于具有处理网络更改能力的移动设备,并在发生数据包丢失时具有良好的恢复能力。在. NET 6 中并没有公开.NET QUIC API,目标是在.NET 7 中公开它们。QUIC 可以像 TCP Socket 一样使用,并不是特定于 HTTP/3,因此我们预计随着时间的推移,其他协议将建立在 QUIC 上,例如QUIC 上的 SMB。
.NET 6 的 HTTP/3 支持
HTTP/3 支持处于预览版状态,因此默认情况下没有启用。由于并非所有路由器、防火墙和代理都能正确地支持 HTTP/3,建议将 HTTP/3 与 HTTP/1.1 和 HTTP/2 一起配置。可通过将 HttpProtocols.Http1AndHttp2AndHttp3
指定为终结点支持的协议来完成此操作。HTTP/3 将 QUIC 用作其传输协议。HTTP/3 的 .NET 实现使用 MsQuic 来提供 QUIC 功能。MSQuic 包含在 Windows 的特定版本中,并作为 Linux 的一个库。如果 Kestrel 所运行的平台没有满足 HTTP/3 的所有要求,则它会被禁用。
例如,HttpProtocols.Http1AndHttp2AndHttp3
允许 Kestrel 在支持 HTTP/3 的环境中启用 HTTP/3,并对 HTTP/1.1 和 HTTP/2 进行回退。
Windows
Windows 11 内部版本 22000 或更高版本和Server 2022 RTM。
TLS 1.3 或更高版本的连接。
上述 Windows 11 内部版本可能需要使用 Windows 预览体验成员内部版本
Linux
在 Linux 上,libmsquic
是通过 Microsoft 官方 Linux 包存储库 packages.microsoft.com
发布的。为了使用它,必须手动添加。请参阅 Microsoft 产品的 Linux 软件存储库。添加 libmsquic
后,可以通过发行版的包管理器安装它,例如,对于 Ubuntu:
sudo apt install libmsquic
macOS
HTTP/3 目前在 macOS 上不受支持,主要是因为缺少与 QUIC 兼容的 TLS API。它可能在未来版本中可用。
Alt-svc
HTTP/3 是通过 alt-svc
标头作为从 HTTP/1.1 或 HTTP/2 的升级发现的。这意味着,在切换到 HTTP/3 之前,第一个请求通常使用 HTTP/1.1 或 HTTP/2。如果启用了 HTTP/3,则 Kestrel 会自动添加 alt-svc
标头。
入门
HTTP/3 是在应用启动时配置的。下面的代码:
将
WebHost
配置为UseQuic
。配置端口 5001 以使用
HttpProtocols.Http1AndHttp2AndHttp3
。
首先要启用预览版特性,添加下列项目属性
<PropertyGroup>
<EnablePreviewFeatures>True</EnablePreviewFeatures>
</PropertyGroup>
public static async Task Main(string[] args)
{
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel((context, options) =>
{
options.Listen(IPAddress.Any, 5001, listenOptions =>
{
// Use HTTP/3
listenOptions.Protocols = HttpProtocols.Http1AndHttp2AndHttp3;
listenOptions.UseHttps();
});
});
}
HTTP/3 Client
HttpClient 已更新,以包括对 HTTP/3 的支持,但它需要启用运行时标记。在项目文件中包括以下内容,以便 HTTP/3 与 HttpClient 配合使用:
<ItemGroup>
<RuntimeHostConfigurationOption Include="System.Net.SocketsHttpHandler.Http3Support" Value="true" />
</ItemGroup>
使用 HttpClient
进行 HTTP/3 请求时,需要额外的配置:
将
HttpClient
.DefaultRequestVersion
设置为 3.0,或者将
HttpClient
.DefaultVersionPolicy
设置为HttpVersionPolicy.RequestVersionExact
。
// See https://aka.ms/new-console-template for more information
using System.Net;
var client = new HttpClient();
client.DefaultRequestVersion = HttpVersion.Version30;
client.DefaultVersionPolicy = HttpVersionPolicy.RequestVersionExact;
var resp = await client.GetAsync("https://localhost:5001/");
var body = await resp.Content.ReadAsStringAsync();
Console.WriteLine($"status: {resp.StatusCode}, version: {resp.Version}, body: {body.Substring(0, Math.Min(100, body.Length))}");
gRpc over HTTP3
gRPC 通常使用 HTTP/2 作为传输工具。HTTP/3 使用相同的语义,因此几乎不需要任何更改就能使其工作。由 .NET 团队提出 HTTP/3 的 gRPC 尚未成为标准:https://github.com/grpc/proposal/pull/256。
.NET 团队将在.NET 7 中进一步开发 QUIC 和 HTTP/3,因此期待在预览过程中得到更新的功能。
相关文章:
https://devblogs.microsoft.com/dotnet/http-3-support-in-dotnet-6/
https://docs.microsoft.com/en-us/aspnet/core/fundamentals/servers/kestrel/http3?view=aspnetcore-6.0