更新- .NET Core 3.0
.NET Core 3.0现在支持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);
原始回答
即使你在请求中明确设置了版本号,也无法在.NET Core 2.1或2.2中使用HttpClient的HTTP/2。你需要显式配置.NET Core以使用随.NET Core 2.0一起提供的旧HttpClientHandler实例,可以通过设置App Context开关来实现:
AppContext.SetSwitch("System.Net.Http.UseSocketsHttpHandler", false);
或者通过将DOTNET_SYSTEM_NET_HTTP_USESOCKETSHTTPHANDLER
环境变量设置为0
或false
。
这个Github问题中的讨论显示,.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 预览版2的官方公告中解释了开关和环境变量:
Sockets Performance and SocketsHttpHandler
We made major improvements to sockets in .NET Core 2.1. Sockets are the basis of both outgoing and incoming networking communication. The higher-level networking APIs in .NET Core 2.1, including HttpClient and Kestrel, are now based on .NET sockets. In earlier versions, these higher-level APIs were based on native networking implementations.
...
You can use one of the following mechanisms to configure a process to use the older HttpClientHandler:
From code, use the AppContext class:
AppContext.SetSwitch("System.Net.Http.UseSocketsHttpHandler", false);
The AppContext switch can also be set by config file.
The same can be achieved via the environment variable DOTNET_SYSTEM_NET_HTTP_USESOCKETSHTTPHANDLER. To opt out, set the value to either false or 0.