更新 - .NET Core 3.0
.NET Core 3.0 现在supports HTTP/2。以下代码将打印2.0:
var client = new HttpClient();
var req = new HttpRequestMessage(HttpMethod.Get, "https://http2.akamai.com/demo"){
Version = new Version(2, 0)
};
var x = await client.SendAsync(req);
var version = x.Version;
Console.WriteLine(version);
原答案
您can't use HTTP/2 with HttpClient in .NET Core 2.1 or 2.2,即使您在请求中明确设置了版本。您必须显式配置 .NET Core 以使用 .NET Core 2.0 附带的 old HttpClientHandler 实例,方法是通过以下方式设置 App Context 开关:
AppContext.SetSwitch("System.Net.Http.UseSocketsHttpHandler", false);
或者通过将DOTNET_SYSTEM_NET_HTTP_USESOCKETSHTTPHANDLER 环境变量设置为0 或false。
this Github issue 中的讨论表明 .NET Core 3.0 计划支持 HTTP/2。 Microsoft Connect 2018 上发布的 3.0 Preview 1 尚不支持 HTTP/2。
HttpClientHandler 使用到 .NET Core 2.0 支持的 HTTP/2。以下代码将在针对 Core 2.0 的项目中返回 2.0:
var client = new HttpClient();
var req = new HttpRequestMessage(HttpMethod.Get, "https://http2.akamai.com/demo")
{
Version = new Version(2, 0)
};
var x = await client.SendAsync(req);
var version = x.Version;
Console.WriteLine(version);
如果您更改目标运行时,请确保彻底清理您的项目 - 删除 bin、obj 和所有目标文件,否则您最终可能会像我一样以错误的运行时运行做了。
在 2.1 中,默认添加了一个新的、速度更快的 SocketsHttpClientHandler。新的处理程序还不支持 HTTP/2。相同的代码将返回1.1 作为协议版本。
如果在创建 HttpClient 之前设置了应用上下文切换,则使用 HTTP/2。此代码将返回 2.0。有趣的是,不需要指定 HTTP 版本。当 HTTP/2 可用时,协商实际的协议版本。即使未指定版本,Akamai URL 和 https://www.google.com 都将使用 HTTP/2:
AppContext.SetSwitch("System.Net.Http.UseSocketsHttpHandler", false);
var client = new HttpClient();
var req = new HttpRequestMessage(HttpMethod.Get, "https://http2.akamai.com/demo");
var x = await client.SendAsync(req);
var version = x.Version;
开关和环境变量在.NET Core 2.1 SDK Preview 2的官方公告中有说明:
Sockets 性能和 SocketsHttpHandler
我们对 .NET Core 2.1 中的套接字进行了重大改进。套接字是传出和传入网络通信的基础。 .NET Core 2.1 中更高级别的网络 API(包括 HttpClient 和 Kestrel)现在基于 .NET 套接字。在早期版本中,这些更高级别的 API 基于本机网络实现。
...
您可以使用以下机制之一来配置进程以使用旧的 HttpClientHandler:
从代码中,使用 AppContext 类:
AppContext.SetSwitch("System.Net.Http.UseSocketsHttpHandler", false);
AppContext 开关也可以通过配置文件来设置。
同样可以通过环境变量 DOTNET_SYSTEM_NET_HTTP_USESOCKETSHTTPHANDLER 来实现。要选择退出,请将值设置为 false 或 0。