我正在尝试通过 HTTP 2.0 请求数据。我正在使用 .Net Core 2.2 中的 HttpClient。我使用的是 Windows 10,但在生产环境中将在 Linux 上运行。问题是响应中的版本似乎始终是“1.1”。我做错了什么?
using (var client = new HttpClient())
{
using (var request = new HttpRequestMessage(new HttpMethod("GET"),
"https://duckduckgo.com/"
))
{
request.Version = new Version(2, 0);
var response = await client.SendAsync(request);
Console.WriteLine(response.Version);
}
}
更新 - .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 中将 HTTP/2 与 HttpClient 一起使用,即使您在请求中显式设置版本也是如此。您必须显式配置 .NET Core 以使用 .NET Core 2.0 附带的old HttpClientHandler 实例,方法是使用 :
设置应用程序上下文开关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 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。
当前建议的模式是在
HttpClient
方法中注册 ConfigureServices
依赖项:https://learn.microsoft.com/en-us/aspnet/core/fundamentals/http-requests。
这是使用类型化客户端注册默认
HttpClient
并将其配置为使用 HTTP/2 的示例:
public void ConfigureServices(IServiceCollection services)
{
...
services.AddHttpClient<ExampleService>()
.ConfigureHttpClient((client) =>
{
client.DefaultRequestVersion = new Version(2, 0);
});
...
}
您想使用 http/2 协议,但没有设置 protocol 属性。请这样做。您是否检查过您使用的操作系统是否可以?例如,.NET Core 尚不支持 Mac 操作系统。另请确保在调用ConfigureKestrel时使用选项变量按照此处所述设置所需的属性。按理说,你也可以尝试这种替代方式来设置http版本。
通过进行curl调用,您可以检查您的http/2调用是否适合您的情况。
此外,.NET Core(您使用的)中的原始 HttpClient 也存在问题。请使用HttpClientFactory。