在.Net中将HTTP 2与HttpClient一起使用

Rob*_*t M 5 http dotnet-httpclient http2 .net-core asp.net-core

我正在尝试通过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);
    }
}
Run Code Online (Sandbox Code Playgroud)

Pan*_*vos 8

Update - .NET Core 3.0

.NET Core 3.0 now supports HTTP/2. The following code will print 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);
Run Code Online (Sandbox Code Playgroud)

Original Answer

You can't use HTTP/2 with HttpClient in .NET Core 2.1 or 2.2, even if you explicitly set the version in the request. You'll have to explicitly configure .NET Core to use the old HttpClientHandler instance that came with .NET Core 2.0, either by setting an App Context switch with :

AppContext.SetSwitch("System.Net.Http.UseSocketsHttpHandler", false);
Run Code Online (Sandbox Code Playgroud)

Or by setting the DOTNET_SYSTEM_NET_HTTP_USESOCKETSHTTPHANDLER environment variable to 0 or false.

The discussion in this Github issue shows that HTTP/2 support is planned for .NET Core 3.0. The 3.0 Preview 1 released at Microsoft Connect 2018 doesn't support HTTP/2 yet.

The HttpClientHandler used up to .NET Core 2.0 supported HTTP/2. The following code will return 2.0 in a project that targets Core 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);
Run Code Online (Sandbox Code Playgroud)

Just make sure you thoroughly clean your project if you change the target runtime - delete bin, obj and all target files, or you may end up running with the wrong runtime as I did.

In 2.1 a new, far faster SocketsHttpClientHandler was added as a default. The new handler doesn't support HTTP/2 yet. The same code will return 1.1 as the protocol version.

If the app context switch is set before creating the HttpClient though, HTTP/2 is used. This code will return 2.0. Interestingly, there's no need to specify the HTTP version. When HTTP/2 is available, the actual protocol version is negotiated. Both the Akamai URL and https://www.google.com will use HTTP/2 even though the version wasn't specified:

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;
Run Code Online (Sandbox Code Playgroud)

The switch and environment variable are explained in the official announcement for .NET Core 2.1 SDK Preview 2:

Sockets Performance and SocketsHttpHandler

We made major improvements to sockets in .NET Core 2.1. Sockets are the basis of both outgoing and incoming networking communication. The higher-level networking APIs in .NET Core 2.1, including HttpClient and Kestrel, are now based on .NET sockets. In earlier versions, these higher-level APIs were based on native networking implementations.

...

You can use one of the following mechanisms to configure a process to use the older HttpClientHandler:

From code, use the AppContext class:

AppContext.SetSwitch("System.Net.Http.UseSocketsHttpHandler", false);
Run Code Online (Sandbox Code Playgroud)

The AppContext switch can also be set by config file.

The same can be achieved via the environment variable DOTNET_SYSTEM_NET_HTTP_USESOCKETSHTTPHANDLER. To opt out, set the value to either false or 0.


小智 5

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);
        });
...
}
Run Code Online (Sandbox Code Playgroud)

  • 适用于除 SendAsync 之外的所有 HttpClient 方法 https://learn.microsoft.com/en-us/dotnet/api/system.net.http.httpclient.defaultrequestversion?view=net-6.0#remarks (4认同)