如何使 .net HttpClient 使用 http 2.0?

How to make the .net HttpClient use http 2.0?

我在 IIS 10(windows 服务器 2016)上托管了一个 asp.net 网站 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?

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

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

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

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

HTTP/2 Support (Windows 10)

HTTP/2 is a new version of the HTTP protocol that provides much better connection utilization (fewer round-trips between client and server), resulting in lower latency web page loading for users. Web pages (as opposed to services) benefit the most from HTTP/2, since the protocol optimizes for multiple artifacts being requested as part of a single experience. HTTP/2 support has been added to ASP.NET in the .NET Framework 4.6. Because networking functionality exists at multiple layers, new features were required in Windows, in IIS, and in ASP.NET to enable HTTP/2. You must be running on Windows 10 to use HTTP/2 with ASP.NET.

HTTP/2 is also supported and on by default for Windows 10 Universal Windows Platform (UWP) apps that use the System.Net.Http.HttpClient API.

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

2.Install WinHttpHandler:

Install-Package System.Net.Http.WinHttpHandler

3.Extend 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.Pass 以上处理程序到 HttpClient 构造函数

using (var httpClient = new HttpClient(new Http2CustomHandler()))
{
      // your custom code
}

WinHttpHandler (), .NET Core 3.0 includes HTTP/2 support in the default SocketsHttpHandler (#30740). Since HTTP/1.1 is still the default, either the default must be changed by setting HttpClient.DefaultRequestVersion, or 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 或任何其他 HttpMessageHandler支持 HTTP/2:

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