asp.net-core - 如何从 Rest API 中过滤掉堆栈跟踪信息并简单地返回 'Status Code: 500; 内部服务器错误'?
问题描述
我有一个 .NET 5 wepapi。我创建了一个全局异常处理程序属性,并将其放在我的基本控制器类中。看起来像这样
public override void OnException(ExceptionContext context)
{
// All user exceptions implement IWebApiException
if (context.Exception is IWebApiException webApiException)
{
// Then return a problem detail
ObjectResult result = new ObjectResult(new ProblemDetails
{
Type = webApiException.Type,
Title = webApiException.Title ?? ReasonPhrases.GetReasonPhrase(webApiException.Status),
Status = webApiException.Status,
Detail = webApiException.Detail,
Instance = webApiException.Instance,
})
{
StatusCode = webApiException.Status
};
result.ContentTypes
.Add(new
MediaTypeHeaderValue(newMicrosoft.Extensions.Primitives.StringSegment("application/problem+json")));
context.Result = result;
}
base.OnException(context);
}
这个想法是开发人员有意抛出的任何异常都将实现IWebApiException
并返回标准问题详细信息。但是,随后抛出了一个未实现的异常,IWebApiException
然后 Rest API 将整个堆栈跟踪返回给调用者,响应如下所示:
System.Exception: Test
at WebApplication1.Controllers.WeatherForecastController.Get() in C:\Dev\Projects\odiam-dot-net-api-starter\API\Controllers\WeatherForecastController.cs:line 58
at lambda_method14(Closure , Object , Object[] )
at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.SyncActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeActionMethodAsync()
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeNextActionFilterAsync()
--- End of stack trace from previous location ---
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync()
--- End of stack trace from previous location ---
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextExceptionFilterAsync>g__Awaited|25_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ExceptionContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeFilterPipelineAsync()
--- End of stack trace from previous location ---
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Builder.Extensions.UsePathBaseMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
相反,我希望返回一条如下所示的简单消息:
Status Code: 500; Internal Server Error
在保持全局异常属性并且不必将每个操作都包装在 try catch 和 return 中的同时,我可以完成此任务的最简单方法是什么new StatusCodeResult(StatusCodes.Status500InternalServerError))
?
解决方案
解决方案比我预期的要简单。我最终创建了一个中间件:
public class ErrorHandlingMiddleware
{
private readonly RequestDelegate next;
public ErrorHandlingMiddleware(RequestDelegate next)
{
this.next = next;
}
public async Task Invoke(HttpContext context)
{
try
{
await next(context);
}
catch (Exception ex)
{
await HandleException(context, ex);
}
}
private static Task HandleException(HttpContext context, Exception ex)
{
// If the exception is not user based
if (ex is not IWebAPiException)
{
// 500 if unexpected
HttpStatusCode code = HttpStatusCode.InternalServerError;
context.Response.ContentType = "text/plain";
context.Response.StatusCode = (int)code;
}
return context.Response.WriteAsync("Status Code: 500; Internal Server Error");
}
}
在管道中注册中间件:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseCors(APIConstants.Cors.AllowAll);
//app.UseDeveloperExceptionPage(); <= remove this line to ensure middleware is used
}
app.UseMiddleware<ErrorHandlingMiddleware>();
...
}
由于所有用户抛出的异常都应该实现IWebApiException
,如果异常没有实现,则返回内部服务器错误 500。
推荐阅读
- actions-on-google - 如何进行“这里的地质情况如何”?
- mysql - Left Join MYSQL Insert 三个条件
- java - 为什么java断言没有效果?
- java - org.modelmapper 中的标记化
- django - 计算 django ManyToMany 关系的“最近使用”
- flutter - 如何从 TextField 小部件的内容创建字符计数器
- sql - 使用 LISTAGG 从已经聚合的 LISTAGG 中删除重复项
- excel - 在 Excel 中查找不间断的子数组 - Kadane 的算法变体?
- smtp - Nodemailer 在本地工作,但在 Netlify 上没有 displayunlockcaptcha 就不能工作
- node.js - Ubuntu 18.04 - npm 更新 - 错误:canvas@2.6.1 安装:`node-pre-gyp install --fallback-to-build`