【问题标题】:Use HTTP 2 with HttpClient in .Net在 .Net 中使用带有 HttpClient 的 HTTP 2
【发布时间】:2018-12-13 14:28:29
【问题描述】:

我正在尝试通过 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);
    }
}

【问题讨论】:

    标签: http asp.net-core .net-core dotnet-httpclient http2


    【解决方案1】:

    更新 - .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 环境变量设置为0false

    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);
    

    如果您更改目标运行时,请确保彻底清理您的项目 - 删除 binobj 所有目标文件,否则您最终可能会像我一样以错误的运行时运行做了。

    在 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。

    【讨论】:

    • 感谢您的回答。根据你说的,我得到了它的工作!在 Windows 10 上。您是否还知道是否有办法让它在 Ubuntu 上运行?我收到了这个错误: System.TypeInitializationException: 'System.Net.Http.CurlHandler' 的类型初始化程序引发了异常。 --> System.TypeInitializationException: 'Http' 的类型初始化器抛出异常。 --> System.TypeInitializationException:“HttpInitializer”的类型初始化程序引发了异常。 --> System.DllNotFoundException: 无法加载共享库“System.Net.Http.Native”或其依赖项之一
    • @RobertM 作为公告和错误解释,如果你想使用旧的 HttpClientHandler,你需要安装旧的先决条件,如 libcurl 和 openssl。旧的 HttpClientHandler 在每个操作系统上使用不同的库。一个快速而肮脏的解决方案可能是先安装 2.0。
    • 非常感谢!确实,在 3.0 之前,使用 2.0 将是最少的头痛方法。
    • 如果您不需要 HTTP/1 兼容性/回退并且不关心某些缺少的功能,您可以尝试我在 C# 中的原生 HTTP/2 实现,它应该可以在 .NET 上运行核心 2.0:github.com/Matthias247/http2dotnet
    【解决方案2】:

    当前建议的模式是在ConfigureServices 方法中注册HttpClient 依赖项:https://docs.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);
            });
    ...
    }
    

    【讨论】:

    【解决方案3】:

    您想使用 http/2 协议,但未设置 protocol property。请这样做。您是否检查过在您使用的操作系统上是否可行? .NET Core does not support 这适用于 Mac OS,例如。还要确保使用选项变量when calling ConfigureKestrel 设置所需的属性,如此处所述。按道理你也可以试试this alternative way设置http版本。

    通过 curl 调用,您可以检查您的http/2 call 是否适合您的情况。

    此外,.NET Core(您使用的)中的原始 HttpClient 存在问题。请使用HttpClientFactory

    【讨论】:

    • 没有“原始”HttpClient。 HttpClientFactory 创建 HttpClient 实例。 2.1 的变化是 HttpClient 默认开始使用新的 SocketClientHandler。
    • Microsoft 的文档引用了“原始且众所周知的 HttpClient 类”。我的意思完全一样,我总是尽量与 Microsoft 文档保持一致,以便人们知道我在说什么。您确实有道理,因为实际上并没有一个新的,只是一种使用您提到的新处理程序创建一个的新方法。 docs.microsoft.com/en-us/dotnet/standard/…
    • 该文档指的是 .NET 4.x HttpClient,而不是 .NET Core。 HttpClientFactory 创建 .NET Core HttpClient 实例。您不能在 .NET Core 中使用旧的 HttpClient 类
    • “原始而知名的 HttpClient 类”是准确的引用。
    • @PanagiotisKanavos,为什么不呢? .Net Core 2.2 缺少什么来支持 HTTP/2?
    猜你喜欢
    • 1970-01-01
    • 2013-05-07
    • 2015-12-17
    • 2021-12-29
    • 2018-05-29
    • 2017-08-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多