如何使 .net HttpClient 使用 http 2.0?

Posted

技术标签:

【中文标题】如何使 .net HttpClient 使用 http 2.0?【英文标题】:How to make the .net HttpClient use http 2.0? 【发布时间】:2015-12-17 13:24:38 【问题描述】:

我有一个托管在 IIS 10(Windows Server 2016)上的 asp.net Web api。当我从 Microsoft Edge 浏览器向它发出 GET 请求时,我看到在 IIS 日志中使用了 HTTP 2.0

2015-09-20 21:57:59 100.76.48.17 GET /RestController/Native - 443 - 73.181.195.76 HTTP/2.0 Mozilla/5.0+(Windows+NT+10.0;+Win64;+x64)+AppleWebKit/537.36+(Khtml,+like+Gecko)+Chrome/42.0.2311.135+Safari/537.36+Edge/12.10240 - 200 0 0 7299

但是,当通过.net 4.6 client 发出GET 请求时,如下所示,

using (var client = new HttpClient())

    client.BaseAddress = new Uri("https://myapp.cloudapp.net/");

    HttpResponseMessage response = await client.GetAsync("RestController/Native");
    if (response.IsSuccessStatusCode)
    
        await response.Content.CopyToAsync(new MemoryStream(buffer));
    

我在服务器日志中看到以下HTTP 1.1登录

2015-09-20 20:57:41 100.76.48.17 GET /RestController/Native - 443 - 131.107.160.196 HTTP/1.1 - - 200 0 0 707

如何让 .net 客户端使用 HTTP/2.0?

【问题讨论】:

【参考方案1】:

HttpClient 还不支持 HTTP/2。它将在下一个版本中提供(代号 KATANA)。这是link to their source code for the next release。

到那时,您可以实现自己的实现 HTTP/2 的 HttpMessageHandler 对象并将其传递给 HttpClient 的构造函数(您可能可以使用来自 KATANA 的源代码)。

【讨论】:

您链接到的 repo 似乎仅适用于服务器组件,而不是客户端(有一个测试客户端,它使用 TcpClient,但不是真正的 HttpClient) @RacilHilan 谢谢你的回答。 “您可以实现自己的实现 HTTP/2 的 HttpMessageHandler 对象”关于您的评论。你能详细说明一下吗? @RashminJaviya 您可以使用我的答案中的链接从他们的源代码中复制代码并将其添加到您的项目中。请记住,代码来自开发,因此您必须自己进行所有测试和可能的修复。显然,这不是一项简单的任务,但当被问到这个问题时,这是唯一的方法。现在,情况发生了变化。如果符合您的需要,请参阅下面 Oliver 的回答。【参考方案2】:

HTTP/2 看起来将在 .NET 4.6.2 的 C# 客户端调用中得到支持

https://msdn.microsoft.com/en-us/library/ms171868(v=vs.110).aspx

HTTP/2 支持(Windows 10)

HTTP/2 是 HTTP 协议的新版本,它提供了更好的 连接利用率(客户端和服务器之间的往返次数减少), 导致用户的网页加载延迟更低。网页(如 与服务相反)从 HTTP/2 中受益最多,因为该协议 针对作为单个请求的一部分请求的多个工件进行优化 经验。 HTTP/2 支持已添加到 .NET 中的 ASP.NET 框架 4.6。因为网络功能存在于多个 层,Windows、IIS 和 ASP.NET 中需要新功能 启用 HTTP/2。您必须在 Windows 10 上运行才能使用 HTTP/2 ASP.NET。

Windows 10 Universal 也支持 HTTP/2,并且默认开启 使用 System.Net.Http.HttpClient 的 Windows 平台 (UWP) 应用 API。

【讨论】:

这只是服务器端,不是客户端。 是的,我正在运行安装了 .net 4.7 的 VS2017,我只看到 HTTP.version 1.0 和 1.1。 看到这条评论:To use HTTP/2 protocol support, you must use .NET Core. You must also use a supported version of Windows 10. And you need to manually specify HttpRequestMessage.Version = new Version(2,0); You can also use the separate System.Net.Http.WinHttpHandler package which provides an alternate handler for HttpClient. You need to create that WinHttpHandler and pass it into the constructor of HttpClient. This WinHttpHandler package is supported on both .NET Core .NET Framework 在这里:github.com/dotnet/corefx/issues/4870 也在同一页:you can use WinHttpHandler on .NET Framework. You must only use the SendAsync() methods from HttpClient. Those are the only ones that allow you to pass in an HttpRequestMessage. Other methods, use a default HttpRequestMessage that uses Version(1,1) only. You have to set the .Version field in HttpRequestMessage to 2.0 as indicated. You have to use a current version of Windows 10.【参考方案3】:

1.确保您使用的是最新版本的Windows 10

2.安装WinHttpHandler

Install-Package System.Net.Http.WinHttpHandler

3.扩展WinHttpHandler添加http2.0支持:

public class Http2CustomHandler : WinHttpHandler

    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
    
        request.Version = new Version("2.0");
        return base.SendAsync(request, cancellationToken);
    

4.将上述处理程序传递给 HttpClient 构造函数

using (var httpClient = new HttpClient(new Http2CustomHandler()))

      // your custom code

【讨论】:

同意,这仍然是在完整的 .net 框架中获得对 HttpClient 的 http2.0 支持的唯一方法 是的,这行得通-谢谢。试图理解为什么 4.72 框架和 win 10 上的 httpclient 在 http2 上不起作用!看起来很疯狂,它不在核心库中,顺便说一句,它安装了很多依赖项。从 4.6 开始测试。 非跨平台 那行得通。但是如果需要管理CookieContainer,还需要将CookieUsePolicy设置为CookieUsePolicy.UseSpecifiedCookieContainer【参考方案4】:

除了WinHttpHandler(as described in Shawinder Sekhon's answer),.NET Core 3.0 中默认includes HTTP/2 supportSocketsHttpHandler(#30740)。由于 the default 在 UWP 之外仍然是 HTTP/1.1,因此必须在每个请求上指定 Version。这可以根据每个请求的需要完成:

using (var client = new HttpClient())

    client.BaseAddress = new Uri("https://myapp.cloudapp.net/");

    HttpResponseMessage response = await client.SendAsync(
        new HttpRequestMessage(HttpMethod.Get, "RestController/Native")
        
            Version = HttpVersion.Version20,
        );
    if (response.IsSuccessStatusCode)
    
        await response.Content.CopyToAsync(new MemoryStream(buffer));
    

或者对所有请求使用自定义HttpMessageHandler,例如:

public class ForceHttp2Handler : DelegatingHandler

    public ForceHttp2Handler(HttpMessageHandler innerHandler)
        : base(innerHandler)
    
    

    protected override Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, CancellationToken cancellationToken)
    
        request.Version = HttpVersion.Version20;
        return base.SendAsync(request, cancellationToken);
    

可以委托给SocketsHttpHandlerWinHttpHandler或任何其他支持HTTP/2的HttpMessageHandler

using (var client = new HttpClient(new ForceHttp2Handler(new SocketsHttpHandler())))

    client.BaseAddress = new Uri("https://myapp.cloudapp.net/");

    HttpResponseMessage response = await client.GetAsync("RestController/Native");
    if (response.IsSuccessStatusCode)
    
        await response.Content.CopyToAsync(new MemoryStream(buffer));
    

【讨论】:

以上是关于如何使 .net HttpClient 使用 http 2.0?的主要内容,如果未能解决你的问题,请参考以下文章

使用 Windows.Web.Http.HttpClient 类 PATCH 异步请求

HttpClient调用.net发布的带Windows NTML验证的webservice

Java如何获取创蓝253短信验证码?

Angular6 - GET net::ERR_CONNECTION_REFUSED 的 HttpClient 错误处理

HttpClient 的 WebAPI 删除列表

C#中HttpClient使用注意:预热与长连接