使用 HttpRequestException 获取失败请求的响应正文

Posted

技术标签:

【中文标题】使用 HttpRequestException 获取失败请求的响应正文【英文标题】:Getting response body on failed request with HttpRequestException 【发布时间】:2016-02-23 21:08:37 【问题描述】:

我正在尝试记录来自我的HttpRequestException 的失败请求。

我的服务器在响应正文中返回错误代码额外的 JSON 负载。我需要访问那个 JSON。如果出现错误请求,如何阅读响应正文?我知道实际的响应不是空的。这是一个 API,我确认它返回带有 4xx 状态代码的 JSON 有效负载,提供有关错误的详细信息。

如何访问它?这是我的代码:

using (var httpClient = new HttpClient())

    try
    
        string resultString = await httpClient.GetStringAsync(endpoint);
        var result = JsonConvert.DeserializeObject<...>(resultString);
        return result;
    
    catch (HttpRequestException ex)
    
        throw ex;
    

我正在尝试在throw ex 行中获取数据,但我找不到方法。

【问题讨论】:

我不知道这是否对你有帮助。 ***.com/questions/10928528/… 【参考方案1】:

正如@Frédéric 建议的那样,如果您使用GetAsync 方法,您将获得正确的HttpResponseMessage 对象,该对象提供有关响应的更多信息。要在发生错误时获取详细信息,您可以将错误反序列化为 Exception 或来自响应内容的自定义异常对象,如下所示:

public static Exception CreateExceptionFromResponseErrors(HttpResponseMessage response)

    var httpErrorObject = response.Content.ReadAsStringAsync().Result;

    // Create an anonymous object to use as the template for deserialization:
    var anonymousErrorObject =
        new  message = "", ModelState = new Dictionary<string, string[]>() ;

    // Deserialize:
    var deserializedErrorObject =
        JsonConvert.DeserializeAnonymousType(httpErrorObject, anonymousErrorObject);

    // Now wrap into an exception which best fullfills the needs of your application:
    var ex = new Exception();

    // Sometimes, there may be Model Errors:
    if (deserializedErrorObject.ModelState != null)
    
        var errors =
            deserializedErrorObject.ModelState
                                    .Select(kvp => string.Join(". ", kvp.Value));
        for (int i = 0; i < errors.Count(); i++)
        
            // Wrap the errors up into the base Exception.Data Dictionary:
            ex.Data.Add(i, errors.ElementAt(i));
        
    
    // Othertimes, there may not be Model Errors:
    else
    
        var error =
            JsonConvert.DeserializeObject<Dictionary<string, string>>(httpErrorObject);
        foreach (var kvp in error)
        
            // Wrap the errors up into the base Exception.Data Dictionary:
            ex.Data.Add(kvp.Key, kvp.Value);
        
    
    return ex;

用法:

        using (var client = new HttpClient())
        
            var response =
                await client.GetAsync("http://localhost:51137/api/Account/Register");


            if (!response.IsSuccessStatusCode)
            
                // Unwrap the response and throw as an Api Exception:
                var ex = CreateExceptionFromResponseErrors(response);
                throw ex;
            
        

这是source 文章,详细介绍了处理 HttpResponseMessage 及其内容。

【讨论】:

【参考方案2】:

使用GetAsync 代替GetStringAsyncGetAsync 不会抛出异常,并允许您访问响应内容、状态代码和您可能需要的任何其他标头。

请参阅此page 了解更多信息。

【讨论】:

【参考方案3】:

基本上是@RyanGunn 发布但在您的代码中实现的内容。

你应该可以从resultString.ContentReadAsStringAsync

我正在开发一个使用类似代码的 SDK,除了我们使用 switch 语句来检查我们打算在 DeserializeObject 行之前返回的各种 HttpStatusCodes

using (var httpClient = new HttpClient())

    try
    
        string resultString = await httpClient.GetStringAsync(endpoint);
        var result = JsonConvert.DeserializeObject<...>(resultString.Content.ReadAsStringAsync().Result);
        return result;
    
    catch (HttpRequestException ex)
    
        throw ex;
    

【讨论】:

以上是关于使用 HttpRequestException 获取失败请求的响应正文的主要内容,如果未能解决你的问题,请参考以下文章

EnsureSuccessStatusCode 的使用和它抛出的 HttpRequestException 的处理

HttpRequestException - 这是客户端还是服务器问题?

使用 HttpClient.GetFromJsonAsync(),如何处理基于 HttpStatusCode 的 HttpRequestException 而无需额外的 SendAsync 调用?

HTTPClient 返回 HttpRequestException WinRT

Polly HandleTransientHttpError 未捕获 HttpRequestException

.NET Core - 在 IIS 上使用 Windows 身份验证从 MVC 应用程序调用 Web API 导致 HttpRequestException 401(未经授权)状态代码