HttpClient在响应流完全读取之前被释放,导致连接关闭异常

Posted

技术标签:

【中文标题】HttpClient在响应流完全读取之前被释放,导致连接关闭异常【英文标题】:HttpClient disposed before response stream fully read, leads to connection closed exception 【发布时间】:2021-07-14 09:53:51 【问题描述】:

我正在尝试将请求的响应流式传输到响应。所以基本上通过管道将请求发送到另一个 url。这是我拥有的代码,它说明了我正在尝试做的事情。

public async Task<IActionResult> GetArticleImage(string userId, string articleId)

    var imageUrl = "https://image-url"; // This url is retrieved from the database
    var imageResult = await this.httpClient.GetAsync(imageUrl);
    var stream = await imageResult.Content.ReadAsStreamAsync();

    return new FileStreamResult(stream, imageResult.Content.Headers.GetValues("Content-Type").First());

在这种情况下会发生ConnectionResetException 被抛出,消息为The client has disconnected

我相信这是因为请求范围在流被完全读取之前被释放,这也释放了HttpClient。 当使用var scope = IServiceScopeFactory.CreateScope()(伪代码,实际上是通过构造函数注入IServiceScopeFactory serviceScopeFactory)创建自定义作用域时,HttpClient 通过那个解析,而不是处置(既不是作用域也不是客户端),它可以正常工作。

值得一提的是,GetArticleImage 方法是在单独的服务类中实现的,不是在控制器中。 以前它是在控制器类中实现的,代码可以完美运行。 这使我假设作用域处置机制的工作方式略有不同,但我不知道如何。

HttpClient 被注册为单例,这应该确保它不会被丢弃。

问题是:如何将请求通过管道传输/流式传输到另一个 url?

调用此方法的端点可以经常被调用,同时有许多请求,所以我想避免将响应缓存在内存中只是为了传递它。

【问题讨论】:

在拨打ReadAsStreamAsync 之前,您是否厌倦了拨打LoadIntoBufferAsync? Reference 你是如何注册你的HttpClient的?这样? services.AddSingleton();你最好使用 services.AddHttpClient(); 注册 httpclient并在您的服务中,注入 IHttpClientFactory,并调用 HttpClientFactory.CreateClient 来创建 httpclient 更多详细信息请参阅此文档:docs.microsoft.com/en-us/aspnet/core/fundamentals/… 还有另一个文档可以参考,说明为什么不应该直接新建 httpclient docs.microsoft.com/en-us/dotnet/architecture/microservices/… 【参考方案1】:

当外部服务与 .Net async/await 一起工作时,有时会发生这种情况

我找到了解决方法(这不是最佳做法)但它对我有用。

public Task<IActionResult> GetArticleImage(string userId, string articleId)

    var imageUrl = "https://image-url"; // This url is retrieved from the database
    var imageResult = this.httpClient.GetAsync(imageUrl).GetAwaiter().GetResult();
    var stream = imageResult.Content.ReadAsStreamAsync().GetAwaiter().GetResult();

    return new FileStreamResult(stream, imageResult.Content.Headers.GetValues("Content-Type").First());

【讨论】:

以上是关于HttpClient在响应流完全读取之前被释放,导致连接关闭异常的主要内容,如果未能解决你的问题,请参考以下文章

释放 HttpClient 4.1.x 的连接以使用一个 HttpClient 实例顺序执行

对象在 PostAsync 与 HttpClient 之后被释放

在内容 100% 完成之前从 HttpResponseMessage 读取标头

HttpClient入门

UWP HttpClient 存储 cookie 直到应用被卸载

从 HTTPClient 响应中解压 GZip 流