【发布时间】:2020-11-17 05:39:07
【问题描述】:
为了重用 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;
}
}
使用此代码,我认为单个 HttpClient 实例将用于相同的请求 url。
但是,Azure 门户上的诊断和解决问题刀片显示 SNAT PORT Exhaustion 发生。
当许多并发请求发生时,这段代码是否会导致此问题?
如果是这样,我如何在 ASP.Net Core 2.0(没有 HttpClientFactory)上创建 HttpClient。
[环境]
- ASP.Net Core 2.0
- Azure WebApps
【问题讨论】:
-
升级到 2.1+ 并然后使用
IHttpClientFactory。 -
@TheGeneral 抱歉..我们的项目无法轻松升级。所以我想知道.net core 2.0 的解决方案。
标签: c# azure azure-web-app-service httpclient asp.net-core-2.0