使用EnsureSuccessStatusCode并处理它抛出的HttpRequestException

时间:2014-01-13 17:34:54

标签: .net httprequest system.net

HttpResponseMessage.EnsureSuccessStatusCode()的使用模式是什么?它处理消息的内容并抛出HttpRequestException,但是我没有看到如何以编程方式处理它而不是通用Exception。例如,它不包括HttpStatusCode,这本来很方便。

有没有办法从中获取更多信息?任何人都可以显示EnsureSuccessStatusCode()和HttpRequestException的相关使用模式吗?

4 个答案:

答案 0 :(得分:120)

当您不希望以任何特定方式处理故障情况时,EnsureSuccessStatusCode的惯用用法是简明地验证请求是否成功。当您想要快速建立客户端原型时,这尤其有用。

当您决定以特定方式处理失败案例时,不要执行以下操作。

var response = await client.GetAsync(...);
try
{
    response.EnsureSuccessStatusCode();
    // Handle success
}
catch (HttpRequestException)
{
    // Handle failure
}

这引发了一个例外,只是为了立即抓住它,这没有任何意义。 IsSuccessStatusCode的{​​{1}}属性就是出于此目的。请执行以下操作。

HttpResponseMessage

答案 1 :(得分:74)

我不喜欢EnsureSuccessStatusCode,因为它不会返回任何有意义的东西。 这就是为什么我创建了自己的扩展程序:

public static class HttpResponseMessageExtensions
{
    public static async Task EnsureSuccessStatusCodeAsync(this HttpResponseMessage response)
    {
        if (response.IsSuccessStatusCode)
        {
            return;
        }

        var content = await response.Content.ReadAsStringAsync();

        if (response.Content != null)
            response.Content.Dispose();

        throw new SimpleHttpResponseException(response.StatusCode, content);
    }
}

public class SimpleHttpResponseException : Exception
{
    public HttpStatusCode StatusCode { get; private set; }

    public SimpleHttpResponseException(HttpStatusCode statusCode, string content) : base(content)
    {
        StatusCode = statusCode;
    }
}

可以找到Microsoft的EnsureSuccessStatusCode源代码here

基于SO link的同步版本:

public static void EnsureSuccessStatusCode(this HttpResponseMessage response)
{
    if (response.IsSuccessStatusCode)
    {
        return;
    }

    var content = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();

    if (response.Content != null)
        response.Content.Dispose();

    throw new SimpleHttpResponseException(response.StatusCode, content);
}

我对IsSuccessStatusCode不喜欢的是,它不是很好的"可重复使用的。例如,您可以使用polly之类的库来解决网络问题时的请求。在这种情况下,您需要您的代码来引发异常,以便polly或其他一些库可以处理它......

答案 2 :(得分:2)

以下是我建议的解决方案。唯一的缺陷是,由于ASP.NET Core框架资源管理器是该框架的内部组件,因此我无法直接重用Microsoft的国际化消息字符串,因此我仅在此处使用逐字英语消息文字。

专业人士

  • 记录5xx服务器错误的内容
    • 有时,服务器错误实际上是变相的客户端错误,例如,客户端使用的端点已弃用,而最终被关闭。
  • 使用ConfigureTestContainer<T>编写集成测试时,更容易发现错误

缺点

  • 效率低下。
    • 如果您阅读了响应内容,并且内容很长,则会使客户端变慢。对于某些具有软实时响应要求的客户,此抖动可能是不可接受的。
  • 对错误日志记录和监视的责任不正确。
    • 如果这是5xx服务器错误,那么为什么客户端会关心,因为客户端没有做错什么?只需调用response.EnsureSuccessStatusCode();,然后让服务器处理即可。
    • 为什么在发生内部服务器错误时不只是检查服务器错误日志?
  • 需要先检查Content属性,然后再检查状态。在某些情况下可能不希望这样做,其中之一就是效率低下。

用法

using (var requestMessage = new HttpRequestMessage(HttpMethod.Post, "controller/action"))
{
  using (var response = await HttpClient.SendAsync(requestMessage))
  {
    var content = await response.Content.ReadAsStringAsync();
    response.EnsureSuccessStatusCode2(content);
    var result = JsonConvert.DeserializeObject<ResponseClass>(content);
  }
}

API

    public static class HttpResponseMessageExtensions
    {
        public static void EnsureSuccessStatusCode2(this HttpResponseMessage message, string content = null)
        {
            if (message.IsSuccessStatusCode)
                return;
            var contentMessage = string.IsNullOrWhiteSpace(content) ? string.Empty : $"Content: {content}";
            throw new HttpRequestException(string.Format(
                System.Globalization.CultureInfo.InvariantCulture,
                "Response status code does not indicate success: {0} ({1}).{2}",
                (int)message.StatusCode,
                message.ReasonPhrase,
                contentMessage)
                );
        }
    }

答案 3 :(得分:0)

当我不想在同一方法上处理Exception时,我使用GuaranteeSuccessStatusCode。

public async Task DoSomethingAsync(User user)
{
    try
    {
        ...
        var userId = await GetUserIdAsync(user)
        ...
    }
    catch(Exception e)
    {
        throw;
    }
}

public async Task GetUserIdAsync(User user)
{
    using(var client = new HttpClient())
    {
        ...
        response = await client.PostAsync(_url, context);

        response.EnsureSuccesStatusCode();
        ...
    }
}

在GetUserIdAsync上引发的异常将在DoSomethingAsync上处理。