如何在ASP上创建HttpClient.Net Core 2.0,以防止Azure WebApps上的SNAT端口耗尽



为了重用HttpClient,我在ASP上创建了一个类似这样的实用程序类。Net Core 2.0。

public class HttpClientUtility
{
private static HttpClientUtility _singleInstance = new HttpClientUtility();
public static HttpClientUtility GetInstance()
{
return _singleInstance;
}
private HttpClientUtility()
{
}
private static readonly ConcurrentDictionary<string, HttpClient> _HttpClientDict = new ConcurrentDictionary<string, HttpClient>();
private HttpClient GetHttpClient(
Uri uri)
{
return _HttpClientDict.GetOrAdd(GetHostCacheKeyFromUri(uri),
(n) =>
{
return new HttpClient();
});
}
private static string GetHostCacheKeyFromUri(
Uri uri)
{
return $"{uri.Scheme}://{uri.DnsSafeHost}:{uri.Port}";
}
private async Task<HttpRequestMessage> CreateRequestMessage(
Uri requestUri,
HttpMethod method,
IEnumerable<KeyValuePair<string, IEnumerable<string>>> headers,
HttpContent content,
bool contentCopy = true
)
{
var requestMessage = new HttpRequestMessage(method, requestUri);
if (headers != null)
{
foreach (var header in headers)
{
requestMessage.Headers.TryAddWithoutValidation(header.Key, header.Value);
}
}
if (content != null)
{
if (contentCopy)
{
var contentStream = new MemoryStream();
await content.CopyToAsync(contentStream);
contentStream.Position = 0;
requestMessage.Content = new StreamContent(contentStream);
if (requestMessage.Content.Headers != null)
{
foreach (var header in content.Headers)
{
requestMessage.Content.Headers.Add(header.Key, header.Value);
}
}
}
else
{
requestMessage.Content = content;
}
}
return requestMessage;
}
public async Task<HttpResponseMessage> SendRequestWithRetry(
Uri requestUri,
HttpMethod method,
HttpContent content,
IEnumerable<KeyValuePair<string, IEnumerable<string>>> headers,
Func<HttpResponseMessage, bool> needRetry)
{
HttpResponseMessage response = null;
var httpClient = GetHttpClient(requestUri);
for (int i = 0; i <= MaxRetryCount; i++)
{
// Create request message for retry
var isPossblRetry = needRetry != null && MaxRetryCount > 0;
var request = await CreateRequestMessage(requestUri, method, headers, content, isPossblRetry).ConfigureAwait(false);
response = await httpClient.SendAsync(request).ConfigureAwait(false);
if (response.IsSuccessStatusCode || needRetry == null || !needRetry(response))
{
break;
}
}
return response;
}
}

有了这段代码,我认为同一个请求url将使用一个HttpClient实例。

但是,Azure门户网站上的诊断和解决问题刀片表示发生了SNAT端口耗尽。

当发生许多并发请求时,此代码是否会导致此问题?

如果是,我该如何在ASP上创建HttpClient。Net Core 2.0(不带HttpClientFactory(。

【环境】

  • ASP。Net Core 2.0
  • Azure WebApps

请确保执行以下步骤:

  • HttpClientUtility作为singleton注入
  • 不要复杂化,只需将new HttpClient()用作静态变量即可。不需要GetHostCacheKeyFromUri

感谢您的回答和评论。但我从MS那里得到了答案。他们说,如果对同一个url的请求超过128,那么即使我使用HttpClientFactory或静态HttpClient,Azure WebApps上也会出现[SNAT端口耗尽]。唯一的解决方案似乎是扩展WebApps或使用ASE。

所以我会按照建议进行编码,并进行扩展。

最新更新