У меня есть приложение .NET Core 2.2, в котором есть контроллер, выступающий в качестве прокси для моих API.
JS делает выборку для прокси, прокси перенаправляет вызов API и возвращает ответ.
Я испытываю периодические блокировки прокси-приложения, когда оно ожидает ответа от HttpClient. Когда это происходит, он блокирует весь сервер. Больше запросов не будет обработано.
Согласно журналам API, который к нему подключается, возвращается нормально.
Чтобы воспроизвести это, я должен сделать 100+ запросов в цикле на клиенте через прокси. Затем я должен перезагрузить страницу несколько раз, перезагружая ее, пока 100 запросов находятся в полете. Обычно требуется около 5 ударов, прежде чем все начинает замедляться.
Прокси-сервер заблокируется в ожидании ожидаемого запроса на разрешение. Иногда он возвращается с задержкой в 4 - 5 секунд, иногда после менуэта. Большую часть времени я не ждал дольше 10 минут, прежде чем сдаться и убить прокси.
Я переместил код в следующий блок, который воспроизведет проблему.
Я полагаю, что я следую передовым методам, его асинхронность полностью снижена, я использую IHttpClientFactory, чтобы обеспечить совместное использование экземпляров HttpClient, я внедряю using
там, где я считаю, что это требуется.
Реализация была основана на этом: https://github.com/aspnet/AspLabs/tree/master/src/Proxy
Я надеюсь, что я делаю довольно очевидную ошибку, что другие с большим опытом могут точно определить!
Любая помощь будет принята с благодарностью.
namespace Controllers
{
[Route("/proxy")]
public class ProxyController : Controller
{
private readonly IHttpClientFactory _factory;
public ProxyController(IHttpClientFactory factory)
{
_factory = factory ?? throw new ArgumentNullException(nameof(factory));
}
[HttpGet]
[Route("api")]
async public Task ProxyApi(CancellationToken requestAborted)
{
// Build API specific URI
var uri = new Uri("");
// Get headers frpm request
var headers = Request.Headers.ToDictionary(x => x.Key, y => y.Value);
headers.Add(HeaderNames.Authorization, $"Bearer {await HttpContext.GetTokenAsync("access_token")}");
// Build proxy request method. This is within a service
var message = new HttpRequestMessage();
foreach(var header in headers) {
message.Headers.Add(header.Key, header.Value.ToArray());
}
message.RequestUri = uri;
message.Headers.Host = uri.Authority;
message.Method = new HttpMethod(Request.Method);
requestAborted.ThrowIfCancellationRequested();
// Generate client and issue request
using(message)
using(var client = _factory.CreateClient())
// **Always hangs here when it does hang**
using(var result = await client.SendAsync(message, requestAborted).ConfigureAwait(false))
{
// Appy data from request onto response - Again this is within a service
Response.StatusCode = (int)result.StatusCode;
foreach (var header in result.Headers)
{
Response.Headers[header.Key] = header.Value.ToArray();
}
// SendAsync removes chunking from the response. This removes the header so it doesn't expect a chunked response.
Response.Headers.Remove("transfer-encoding");
requestAborted.ThrowIfCancellationRequested();
using (var responseStream = await result.Content.ReadAsStreamAsync())
{
await responseStream.CopyToAsync(responseStream, 81920);
}
}
}
}
}
EDIT
Таким образом, код был изменен, чтобы удалить употребления и вернуть прокси-ответ непосредственно в виде строки вместо потоковой передачи и при этом получать те же проблемы.
При запуске netstat я вижу множество журналов для URL прокси-API.
В 4 строках указывается IP-адрес прокси-API, вероятно, еще в 20 строках указывается IP-адрес прокси-сайта. Эти цифры не кажутся мне странными, но у меня нет большого опыта использования netstat (впервые я его запустил).
Также я оставил прокси включенным около 20 минут. Это технически все еще жив. Ответы возвращаются. Прошло очень много времени между прокси API для возврата данных и разрешением HttpClient. Однако он не будет обслуживать любые новые запросы, они просто сидят и висят.