如何解决在 Web API 调用导致异常后处理响应中的内容的最佳实践 步骤 #1第 2 步步骤 #3
我正在研究 Core 3.1 Web API 和使用它的 MVC 应用程序。在 MVC 应用程序中,我设置了 UserRepo
,其中包含向 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();
,这很有效。
但是,异常不包含我需要找出 API 调用出了什么问题的内容。如果发生 400 错误,则会抛出异常,说明发生了 400 错误,但不会为什么发生。 why 返回到 response
变量,由于我已经实施了验证,它可能看起来像这样:
{
"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 错误,所以我知道要修复什么。我只是不知道处理这些响应消息的“正确”方式是什么。
我的一个想法是在每次抛出异常之前捕获异常并将其与响应文本一起记录。然后当我的应用程序崩溃时,我可以转到日志并阅读返回的消息。 Update
方法如下所示:
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>();
}
另一个想法是,也许可以将消息添加到异常本身并在抛出时查看它?将消息添加为内部异常是否有意义?
解决方法
是否有一种广泛使用的方法来处理在 API 中产生错误后返回的响应?我想知道为什么会出现 400 错误,所以我知道要修复什么。我只是不知道处理这些响应消息的“正确”方式是什么。
一般情况下,异常详细信息只会被记录下来,不会被返回。这是因为详细信息可能包括可能揭示潜在安全漏洞的个人身份信息或技术细节。有一个 error details RFC 变得越来越普遍,但即使如此也不应该包含诸如 PII 或堆栈跟踪之类的详细信息。
在一个 API(MVC 端点)调用另一个 API(实际 API)的情况下,MVC 端点应返回 5xx 范围内的代码。这里可以接受 500 或 502。所有此类错误及其详细信息都应记录在服务器端。
请注意,如果传播异常,默认行为是返回 500,因此保留 throw;
才是您真正需要做的。但是,在“管道”中执行错误 logging 是正常的,例如,ASP.NET Core 的中间件或 ASP.NET MVC 的全局安装操作过滤器之类的东西。这是为了确保记录所有错误,同时避免重复。
EnsureSuccessStatusCode
与 2xx 不同,HttpRequestException
会抛出一个 StatusCode
。
为了从响应中获得最多的信息,您必须手动检索它。
一般流程可以用以下方式描述:
- 在 try-catch 块内发出请求。
- 如果没有异常,则检查响应的 statusCode。
- 如果它与预期的不同,则尝试读取响应的正文
并记录所有内容。
步骤 #1
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
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。