Web API调用导致异常后处理响应中内容的最佳实践 [英] Best practice to handle content in the response after a Web API call results in an exception

查看:85
本文介绍了Web API调用导致异常后处理响应中内容的最佳实践的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在研究Core 3.1 Web API和使用它的MVC应用程序.在MVC应用中,我设置了 UserRepo ,其中包含将请求发送到API的方法:

I'm working on a Core 3.1 Web API and an MVC application that uses it. In the MVC app I have UserRepo set up containing methods that send requests to the API:

public class UserRepo : IUserRepo
{
    private readonly IHttpClientFactory _clientFactory;

    public UserRepo(IHttpClientFactory httpClientFactory)
    {
        _clientFactory = httpClientFactory;
    }

    public async Task<User> GetById(int Id)
    {
        // same code structure as Update ...
    }

    public async Task<User> Update(User user)
    {
        HttpClient client = _clientFactory.CreateClient("NamedClient");

        try
        {
            HttpResponseMessage response = await client.PutAsync($"api/Users/{user.Id}", ContentEncoder.Encode(user));
            return await response.Content.ReadFromJsonAsync<User>();
        }
        catch (Exception ex)
        {
            throw;
        }

    }

    public async Task<User> Insert(User user)
    {
        // same code structure as Update ...
    }
}

Update 方法绝不会抛出从API返回的错误(例如400、404等),从而导致无提示错误.我发现要导致异常,我需要调用有效的 response.EnsureSuccessStatusCode(); .

The Update method never throws errors like 400, 404, etc, that come back from the API, resulting in silent errors. I found that to cause exceptions I need to call response.EnsureSuccessStatusCode();, which worked.

但是,异常不包含我需要找出API调用出了什么问题的内容.如果发生400错误,则会引发一个异常,指出发生了400错误,但没有为什么发生.为什么返回到 response 变量,由于我已经实现了验证,它可能看起来像这样:

However, the exception doesn't contain what I need to find out what went wrong with the API call. If a 400 error occurs, an exception will be thrown saying that 400 error occurred, but not why it occurred. The why is returned to the response variable and it may look something like this due to validation I have implemented:

{
  "errors": {
    "FirstName": [
      "The FirstName field is required."
    ]
  },
  "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
  "title": "One or more validation errors occurred.",
  "status": 400,
  "traceId": "|502d647b-4c7425oa321c8c7b."
}

是否存在一种广泛使用的方法来处理在API中产生错误后返回的响应?我想知道为什么发生400错误,所以我知道要解决的问题.我就是不知道什么是正确的".处理这些响应消息的方式.

Is there a widely used way to handle the response that comes back after an error is produced in the API? I want to know why a 400 error occurred so I know what to fix. I just don't know what is the "right" way to handle these response messages.

我的一个主意是捕获异常,并在抛出异常之前每次都将其与响应文本一起记录下来.然后,当我的应用程序崩溃时,我可以转到日志并阅读返回的消息. Update 方法如下所示:

One idea I had was to catch the exception and log it along with the response text every time before throwing it. Then when my app crashes I can go to the logs and read the message returned. The Update method would look like this:

public async Task<User> Update(User user)
{
    HttpClient client = _clientFactory.CreateClient("NamedClient");

    HttpResponseMessage response = await client.PutAsync($"api/Users/{user.Id}", ContentEncoder.Encode(user));

    try
    {
        response.EnsureSuccessStatusCode();
    }
    catch (Exception ex)
    {
        string errorMessage =  await response.Content.ReadAsStringAsync()
        _logger.LogError(ex, errorMessage);
        throw;
    }

    return await response.Content.ReadFromJsonAsync<User>();
}

另一种想法可能是可以将消息添加到异常本身,并在引发异常时看到它?将消息添加为内部异常是否有意义?

Another thought that came would be maybe it's possible to add the message to the exception itself and see it when it's thrown? Would it make sense to add the message as an inner exception?

推荐答案

EnsureSuccessStatusCode 会引发 HttpRequestException .

为了从响应中获取最多的信息,您必须手动检索它.

In order to gain the most information from the response, you have to retrieve it manually.

一般流程可以通过以下方式描述:

The general flow could be described in the following way:

  1. 在try-catch块中发出请求.
  2. 如果没有异常,则检查响应的statusCode.
  3. 如果它与预期的不同,则尝试读取响应的正文

并记录所有内容.

HttpResponseMessage response = null;  
try
{
    response = await httpClient.PutAsync(...);
}
catch (InvalidOperationException ioEx)
{
    //The request message was already sent by the HttpClient instance, but failed due to some protocol violation
    HttpClient.CancelPendingRequests();
    
    //TODO: logging
}
catch (TaskCanceledException tcEX) 
{
    //The request was not completed due to either it's timed out or cancelled
    if(!tcEX.CancellationToken.IsCancellationRequested)
        HttpClient.CancelPendingRequests();
    
    //TODO: logging
}
catch (HttpRequestException hrEx)
{
    //The request failed due to an underlying issue such as network connectivity, DNS failure, server certificate validation.
    
    //TODO: logging
}

步骤2

HttpStatusCodes[] validResponseCodes = new [] {
     HttpStatusCode.OK, 
     HttpStatusCode.Created,
     HttpStatusCode.NoContent,
};

if(!validResponseCodes.Contains(response?.StatusCode))
{
    //Step #3
}

步骤#3

string errorResponse = await response.Content.ReadAsStringAsync();
//Try to parse it if you know the structure of the returned json/xml/whatever

这篇关于Web API调用导致异常后处理响应中内容的最佳实践的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆