为什么 HttpClientHandler 没有正确选取和使用默认代理设置?



我们有许多.NET Core 2.1服务,以及某些.NET Framework 4.7.1在客户的Windows Server上运行的应用程序(我认为2016年(框。客户设置了一个代理设置(通过控制面板>代理设置> LAN设置(,所有流量都需要使用。所有这些服务都向云打来电话。

我们看到的是,来自.NET核心服务的一些呼叫正在到达云(例如我们可以查看的日志记录(,但是大多数其他呼叫都在计时。.NET框架应用程序我们没有任何这些问题。

所有服务/应用程序都使用httpclient(在每个应用程序中进行单个实例(使用httprequestmessage请求,而不是httpwebrequeast对象。我已经读到,如果您使用httpclienthandler初始化httpclient并将useproxy属性设置为true,并且将代理属性设置为null,则应使用Windows中设置的默认代理设置,我相信您不相信您不初始化该设置httpclient带有httpclienthandler,它将使用默认的效果。

我们通过制作测试.NET Core Console应用程序并对许多云服务进行调用,使HTTPCLCCLIENT如何使用默认代理设置来追踪问题。有趣的是,似乎使用了默认的代理设置,因为第一个呼叫按预期工作。但是,此后的每个呼叫(对不同的云服务(的失败方式与完全不使用代理设置的方式完全相同。

我们通过实际提供将HTTPClientHandler对象提供给HTTPCLIENT的HTTPCLIENTHANDLER对象,该对象使用配置为使用正确的代理的WebProxy对象来解决此问题。设置此设置后,所有呼叫都成功。这不是首选解决方案,因为它涉及客户必须为每种服务提供额外的配置。他们还不一定知道这些服务将运行哪台机器,并且在配置服务时可能不知道代理设置。

,我们还通过在每个呼叫后处理HTTPCLIENT并实例化新问题,以另一种方式解决了问题。显然,这不是解决方案,因为这是不良的实践,并且可能导致其他问题(并且会涉及多个依赖性的许多代码更改(。

当我们将.NET Core 2.1控制台应用程序转换为.NET Framework 4.7.1应用程序时,我们也不会看到问题。

如果使用httpwebrequest对象提出请求。

,我们也不会看到任何问题。

这是当前失败的控制台应用程序代码。我们在服务中正确使用异步,而不是调用结果。这似乎没有区别。

var httpClient = new HttpClient();
Console.WriteLine("Hitting service 1 API");
var request = new HttpRequestMessage(HttpMethod.Get, $"{baseUrl}/service1/serviceinfo");
var result = httpClient.SendAsync(request).Result;
Console.WriteLine($"Response code: {result.StatusCode}");           
var responseMessage = result.Content.ReadAsStringAsync().Result;
Console.WriteLine(responseMessage);
Thread.Sleep(2000);
Console.WriteLine("Hitting service 2 API");
request = new HttpRequestMessage(HttpMethod.Get, $"{baseUrl}/service2/serviceinfo");
result = httpClient.SendAsync(request).Result;
Console.WriteLine($"Response code: {result.StatusCode}");          
responseMessage = result.Content.ReadAsStringAsync().Result;
Console.WriteLine(responseMessage);            
Thread.Sleep(2000);
Console.WriteLine("Hitting service 3 API");
request = new HttpRequestMessage(HttpMethod.Get, $"{baseUrl}/service3/serviceinfo");
result = httpClient.SendAsync(request).Result;
Console.WriteLine($"Response code: {result.StatusCode}");            
responseMessage = result.Content.ReadAsStringAsync().Result;
Console.WriteLine(responseMessage);

预期结果:无论您是否配置了代理人,这三个电话都应通过并接收200个响应。

实际结果:当不使用代理时,我们会得到预期的结果,尽管使用代理时,第一个呼叫会按预期成功,但是下一个呼叫会在我们的本地测试机上使用SocketException或客户计算机上的GatewayTime Out失败(我相信这只是我们阻止所有未通过代理的流量的方式(。

如果每个调用使用新的httpclient,则会发生预期结果。

如果使用httpwebrequest而不是使用httpclient

,则会发生预期结果

如果使用具有明确设置的代理设置的httpclienthandler初始化httpclient,则会发生预期结果。

在进行更多挖掘之后,我们找到了以下解决方案:

AppContext.SetSwitch("System.Net.Http.UseSocketsHttpHandler", false);

显然在.NET Core 2.1中,HTTPClient被迫使用新的HTTPClientHandler。您可以使用上面的AppContext开关,也可以使用旧处理程序初始化httpclient。这似乎是带有.NET核心的明确错误/回归,但我知道我似乎找不到在线上有这个确切问题的其他人。欢迎更多建议。也许是一个错误需要报告?

最新更新