当状态码不为成功时无法读取HttpResponseMessage内容

7

我有一个服务,它正在使用 HttpClient 调用短信 REST API:

HttpClient http = this._httpClientFactory.CreateClient();
// Skipped: setup HttpRequestMessage
using (HttpResponseMessage response = await http.SendAsync(request))
{
    try
    {
        _ = response.EnsureSuccessStatusCode();
    }
    catch (HttpRequestException)
    {
        string responseString = await response.Content.ReadAsStringAsync(); // Fails with ObjectDisposedException
        this._logger.LogInformation(
            "Received invalid HTTP response status '{0}' from SMS API. Response content was {1}.",
            (int)response.StatusCode,
            responseString
        );
        throw;
    }
}

API返回了错误,但我希望能够记录它。因此,我需要同时记录失败的状态码(可以从response.StatusCode中读取)和相关内容(可能包含其他有用的错误详情)。
这段代码在指令await response.Content.ReadAsStringAsync()上失败,并提示以下异常信息:

System.ObjectDisposedException: Cannot access a disposed object.
Object name: 'System.Net.Http.HttpConnection+HttpConnectionResponseContent'.
    Module "System.Net.Http.HttpContent", in CheckDisposed
    Module "System.Net.Http.HttpContent", in ReadAsStringAsync

一些来源表示,在状态码不在成功范围(200-299)内时,您不应该读取响应内容,但如果响应确实包含有用的错误详细信息怎么办?
.NET版本:AWS Lambda Linux运行时上的.NET Core 2.1.12。

为什么不在抛出异常之前先阅读内容呢?然后将内容传递给异常,这样您就可以在catch块中访问它。 - Johnathan Barclay
你是否意味着 EnsureSuccessStatusCode() 会释放响应? - Maxime Rossini
1个回答

9

好的,显然这是.NET API中已知的问题(一个已知的问题),这个问题在.NET Core 3.0中得到了解决。 response.EnsureSuccessStatusCode()实际上正在处置响应内容。据说采用这种方式是为了帮助用户:

// 处置内容应该有助于用户:如果用户调用EnsureSuccessStatusCode(),并且响应状态码不是2xx,则会抛出异常。
// 即行为类似于请求失败(例如连接失败)。在这种情况下,用户不希望处置内容:如果抛出异常,对象要负责清理其状态。

这是一种不良行为,已从3.0中删除。同时,在记录日志之前,我切换使用IsSuccessStatusCode

HttpClient http = this._httpClientFactory.CreateClient();
// Skipped: setup HttpRequestMessage
using (HttpResponseMessage response = await http.SendAsync(request))
{
    if (!response.IsSuccessStatusCode)
    {
        string responseString = await response.Content.ReadAsStringAsync(); // Fails with ObjectDisposedException
        this._logger.LogInformation(
            "Received invalid HTTP response status '{0}' from SMS API. Response content was {1}.",
            (int)response.StatusCode,
            responseString
        );
        _ = response.EnsureSuccessStatusCode();
    }
}

有点多余,但应该可以工作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接