我有一个.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);
}
}
}
}
}
编辑
因此修改了代码以删除用法,并直接以字符串形式而不是流方式返回代理响应,并且仍然遇到相同的问题。
运行netstat时,我确实看到很多代理API网址的日志。
4行提到要代理的API的IP,大概另外20行提到代理站点的IP。这些数字对我来说似乎并不奇怪,但我在使用netstat时没有太多经验(我第一次把它开除)。
我还让代理运行了大约20分钟。从技术上讲,它仍然有效。回应又回来了。从将API代理到返回数据与HttpClient解析之间只花了很长时间。但是,它不会处理任何新请求,它们只是挂在那儿。