静态HttpClient仍然创建TIME_WAIT tcp端口

我正在使用.NET Framework中的HttpClient(4.5.1 +,4.6.1和4.7.2)遇到一些有趣的行为。 我已经提议在工作中的一些项目中进行一些更改,以便在每次使用时不处理HttpClient,因为TCP端口使用率很高的已知问题,请参阅https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong / 。

我已经调查了这些更改,以检查事情是否按预期工作,并发现我们仍然遇到与以前相同的TIME_WAIT端口。

为了确认我提出的更改是正确的,我已经向应用程序添加了一些额外的跟踪,以确认我在整个应用程序中使用了相同的HttpClient实例。 我已经使用过简单的测试应用程序(取自上面链接的aspnetmonsters网站。

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

仅当使用Windows身份validation连接到IIS中承载的站点时,才会出现此问题。 通过将身份validation设置为匿名(问题消失)并返回到Windows身份validation(问题重新出现),我可以轻松地重现问题。

Windows身份validation的问题似乎不仅限于提供程序的范围。 如果您使用Negotiate或NTLM,它也会遇到同样的问题。 如果机器只是工作站或域的一部分,也会出现问题。

出于兴趣,我创建了一个dotnet核心2.1.0控制台应用程序,该问题根本不存在,并按预期工作。

TLDR:有没有人知道如何解决这个问题,或者它可能是一个错误?

精简版

如果要使用NTLM身份validation重用连接,请使用.NET Core 2.1

长版

当使用NTLM身份validation时,我很惊讶地发现“旧的”HttpClient确实为每个请求使用了不同的连接。 这不是一个错误 – 在.NET Core 2.1 HttpClient使用HttpWebRequest之前,它会在每次NTLM身份validation调用后关闭连接。

HttpWebRequest.UnsafeAuthenticatedConnectionSharing属性的文档中对此进行了描述,该属性可用于启用共享连接:

此属性的默认值为false,这会导致在请求完成后关闭当前连接。 每次发出新请求时,您的应用程序都必须经过身份validation序列。

如果此属性设置为true,则在执行身份validation后,用于检索响应的连接将保持打开状态。 在这种情况下,将此属性设置为true的其他请求可以使用该连接而无需重新进行身份validation。

风险在于:

如果已经为用户Avalidation了连接,则用户B可以重用A的连接; 基于用户A的凭证完成用户B的请求。

如果理解风险,并且应用程序使用模拟,可以使用WebRequestHandler配置HttpClient并设置UnsafeAuthenticatedConnectionSharing ,例如:

 HttpClient _client; public void InitTheClient() { var handler=new WebRequestHandler { UseDefaultCredentials=true, UnsafeAuthenticatedConnectionSharing =true }; _client=new HttpClient(handler); } 

WebRequestHandler 公开允许例如通过ID对连接进行分组的HttpWebRequest.ConnectionGroupName ,因此它无法处理模拟。

.NET Core 2.1

HttpClient在.NET Core 2.1中重写,并使用套接字,最小分配,连接池等实现所有HTTP,网络function。它还单独处理NTLM质询/响应流,因此可以使用相同的套接字连接来提供不同的经过身份validation的请求。

如果有人感兴趣,你可以追逐从HttpClient到SocketsHttpHanlder到HttpConnectionPoolManager,HttpConnectionPool,HttpConnection,AuthenticationHelper.NtAuth的调用,然后再回到HttpConnection发送原始字节。