你能用.Net Core HttpClient实现Http/2多路复用吗?

Posted

技术标签:

【中文标题】你能用.Net Core HttpClient实现Http/2多路复用吗?【英文标题】:Can you achieve Http/2 multiplexing with .Net Core HttpClient? 【发布时间】:2018-05-29 13:47:41 【问题描述】:

总结

Http/2 协议提供了通过单个连接多路复用多个请求的能力。这允许更有效地使用连接 - 请参阅https://http2.github.io/faq/#why-is-http2-multiplexed

我希望能够使用 .Net Core HttpClient 来实现这一点。然而,我的测试(基于以下)表明请求与 TCP 连接的比例为 1:1。

.Net Core HttpClient 下是否支持多路复用?如果是这样,它是如何实现的?

工作至今

我有一个示例应用程序(repo 可以找到here,代码如下;

using (var httpClient = new HttpClient())

   var request1 = new HttpRequestMessage(HttpMethod.Get, "https://www.google.com");
   request1.Version = new Version(2, 0);

   var request2 = new HttpRequestMessage(HttpMethod.Get, "https://www.google.com");
   request2.Version = new Version(2, 0);

   var task1 = httpClient.SendAsync(request1);
   var task2 = httpClient.SendAsync(request2);

   Task.WaitAll(task1, task2);

   var response1 = task1.Result;
   var response2 = task2.Result;

   Console.WriteLine($"Response 1 - Http Version: response1.Version, Http Status Code: response1.StatusCode");
   Console.WriteLine($"Response 2 - Http Version: response2.Version, Http Status Code: response2.StatusCode");

此代码产生以下结果(所以我知道正在使用 Http/2);

Response 1 - Http Version: 2.0, Http Status Code: OK
Response 2 - Http Version: 2.0, Http Status Code: OK

我可以从 Wireshark 看到已经创建了 2 个连接 - 每个都必须通过 TLS 设置;

如果 HttpClient 多路复用请求,我希望看到一个连接(1 个端口、1 个握手等)。

【问题讨论】:

我必须添加新的 WinHttpHandler() 作为处理程序才能获得 2.0,你知道为什么吗? 【参考方案1】:

我的代码的问题是HttpClient 在有机会为request1 创建TCP 连接之前收到request2。因此,就HttpClient 而言,没有现有的多路复用连接。

但是,如果我创建了一个初始请求(下面的 request0)并允许 HttpClient 打开连接,那么后续请求(1 和 2)将使用该现有连接。

代码:

using (var httpClient = new HttpClient())

   // Setup first connection
   var request0 = new HttpRequestMessage(HttpMethod.Get, "https://www.google.com");
   request0.Version = new Version(2, 0);

   var task0 = httpClient.SendAsync(request0);
   var response0 = task0.Result;

   Console.WriteLine($"Response 0 - Http Version: response0.Version, Http Status Code: response0.StatusCode");

   // Now send the multiplexed requests
   var request1 = new HttpRequestMessage(HttpMethod.Get, "https://www.google.com");
   request1.Version = new Version(2, 0);

   var request2 = new HttpRequestMessage(HttpMethod.Get, "https://www.google.com");
   request2.Version = new Version(2, 0);

   var task1 = httpClient.SendAsync(request1);
   var task2 = httpClient.SendAsync(request2);

   Task.WaitAll(task1, task2);

   var response1 = task1.Result;
   var response2 = task2.Result;

   Console.WriteLine($"Response 1 - Http Version: response1.Version, Http Status Code: response1.StatusCode");
   Console.WriteLine($"Response 2 - Http Version: response2.Version, Http Status Code: response2.StatusCode");

以及 Wireshark 证明(仅 1 个端口,1 次握手):

【讨论】:

限制 MaxConnectionsPerServer 也会强制多路复用。默认值为 2147483647。var handler = new WinHttpHander(); handler.MaxConnectionsPerServer = 1; var httpClient = new HttpClient(handler); 摇滚老兄,感谢分享这项研究。只是为了让其他人清楚:此答案中的固定代码在以下行之后是相同的:“//现在发送多路复用请求” 您只看到一个连接这一事实并不意味着它是多路复用的。 HTTP 连接具有保持活动的行为,可以在同一连接上发出多个请求(不管流水线或多路复用)。你看到的会是这样吗?或者您是否验证了请求或响应实际上是在流中交错的? 当您在 HTTPClientRequest 上明确指定使用版本 2 时,如果服务器不支持 HTTP 2,它将如何处理这种情况 @AndrewArnott,完全同意...我试图证明多路复用一整天,为此我们必须在 WireShark 中解密 TLS...听起来可以使用自定义本地服务器也支持多路复用

以上是关于你能用.Net Core HttpClient实现Http/2多路复用吗?的主要内容,如果未能解决你的问题,请参考以下文章

.NET Core - HttpClient 与 RestSharp [关闭]

.Net Core 3.0后台使用httpclient请求网络网页和图片_使用Core3.0做一个简单的代理服务器

如何在ASP.NET Core 中使用IHttpClientFactory

将客户端证书添加到 .NET Core HttpClient

asp.net core 使用HttpClientFactory Polly实现熔断降级

.NET Core Httpclient 有效,但 .Net Framework 4.7.2 httpclient 无效