问题描述
我正在使用.NET Framework的HttpClient(4.5.1 +,4.6.1和4.7.2)遇到一些有趣的行为。由于TCP端口使用率较高的已知问题,我在工作中的项目中提出了一些更改,以免每次使用时都丢弃HttpClient,请参见。
I am experiencing some interesting behavior with the HttpClient from the .NET Framework (4.5.1+, 4.6.1 and 4.7.2). I have proposed some changes in a project at work to not dispose of the HttpClient on each use because of the known issue with high TCP port usage, see https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/.
我研究了这些更改,以检查事情是否按预期进行,并发现我们仍然遇到与以前相同的TIME_WAIT端口。
I have investigated the changes to check that things were working as expected and found that we are still experiencing the same TIME_WAIT ports as before.
为确认我建议的更改是正确的,我向应用程序添加了一些额外的跟踪,以确认我在整个应用程序中使用的是HttpClient的相同实例。此后,我使用了简单的测试应用程序(来自上面链接的aspnetmonsters网站。
To confirm that my proposed changes were correct I have added some extra tracing to the application that confirm that I am using the same instance of the HttpClient through out the application. I have since used simple test application (taken from the aspnetmonsters site linked above.
using System;
using System.Net.Http;
namespace ConsoleApplication
{
public class Program
{
private static HttpClientHandler { UseDefaultCredentials = true };
private static HttpClient Client = new HttpClient(handler);
public static async Task Main(string[] args)
{
Console.WriteLine("Starting connections");
for(int i = 0; i<10; i++)
{
var result = await Client.GetAsync("http://localhost:51000");
Console.WriteLine(result.StatusCode);
}
Console.WriteLine("Connections done");
Console.ReadLine();
}
}
}
仅当使用Wi连接到IIS托管的站点时,才会出现此问题。身份验证。我可以通过将身份验证设置为匿名(问题消失)并返回到Windows身份验证(问题再次出现)来轻松重现该问题。
The issue only occurs when connecting to a site that is hosted in IIS using Windows Authentication. I can reproduce the issue easily by setting the Authentication to Anonymous (problem goes away) and back to Windows Authentication (problem reoccurs).
Windows身份验证似乎没有问题限于提供者的范围。如果您与我们进行谈判或与NTLM进行通讯,则会遇到相同的问题。如果计算机只是工作站或域的一部分,也会发生此问题。
The issue with Windows Authentication does not seem to be limited to the scope of the provider. It has the same issue if you us Negotiate or NTLM. Also the issue occurs if the machine is just a workstation or part of a domain.
出于兴趣,我创建了一个dotnet core 2.1.0控制台应用程序,但问题不是
Out of interest I created a dotnet core 2.1.0 console app and the issue is not present at all and works as expected.
TLDR:是否有人对如何解决此问题有任何想法,或者可能是一个错误?
TLDR: Does any one have any idea on how to fix this, or is it likely to be a bug?
推荐答案
简短版本
使用.NET Core 2.1如果您想重用NTLM身份验证进行连接
Use .NET Core 2.1 if you want to reuse connections with NTLM authentication
长版
看到使用NTLM身份验证的旧 HttpClient确实为每个请求使用了不同的连接,我感到非常惊讶。这不是错误-在.NET Core 2.1 HttpClient使用HttpWebRequest之前,它将在每次NTLM身份验证调用后关闭连接。
I was quite surprised to see that the "old" HttpClient does use a different connection for each request when NTLM authentication is used. This isn't a bug - before .NET Core 2.1 HttpClient would use HttpWebRequest which closes the connection after every NTLM authenticated call.
这在属性,可用于启用连接共享:
This is described in the documentation of the HttpWebRequest.UnsafeAuthenticatedConnectionSharing property which can be used to enable sharing of the connection :
如果此属性设置为true,则用于获取响应的连接在打开后将保持打开状态。身份验证已执行。在这种情况下,将此属性设置为true的其他请求可能会使用该连接,而无需重新进行身份验证。
If this property is set to true, the connection used to retrieve the response remains open after the authentication has been performed. In this case, other requests that have this property set to true may use the connection without re-authenticating.
风险是:
如果一个人理解风险,并且应用程序使用假冒,可以使用并设置,例如:
If one understands the risks, and the application doesn't use impersonation, one could configure HttpClient with a WebRequestHandler and set the UnsafeAuthenticatedConnectionSharing, eg :
HttpClient _client;
public void InitTheClient()
{
var handler=new WebRequestHandler
{
UseDefaultCredentials=true,
UnsafeAuthenticatedConnectionSharing =true
};
_client=new HttpClient(handler);
}
WebRequestHandler 不公开允许对连接进行分组,例如
WebRequestHandler doesn't expose the HttpWebRequest.ConnectionGroupName that would allow to group connections eg by ID, so it can't handle impersonation.
.NET Core 2.1
HttpClient在.NET Core 2.1中进行了重写,并实现了所有HTTP,使用套接字的网络功能,最小分配,连接池等。它还处理分开,因此相同的套接字连接可以用于满足不同的身份验证请求。
HttpClient was rewritten in .NET Core 2.1 and implements all the HTTP, networking functionality using sockets, minimal allocations, connection pooling etc. It also handles the NTLM challenge/response flow separatelly so the same socket connection can be used to serve different authenticated requests.
如果有人感兴趣,您可以跟踪从HttpClient到SocketsHttpHanlder到HttpConnectionPoolManager,HttpConnectionPool,HttpConnection,AuthenticationHelper.NtAuth的调用,然后再返回HttpConnection发送原始字节。
If anyone is interested, you can chase the calls from HttpClient to SocketsHttpHanlder to HttpConnectionPoolManager , HttpConnectionPool, HttpConnection, AuthenticationHelper.NtAuth and then back to HttpConnection to send the raw bytes.
这篇关于静态HttpClient仍在创建TIME_WAIT tcp端口的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!