繁体   English   中英

在 Angular 和 .Net Core API 中显示自定义服务器端错误消息

[英]Displaying Custom Server Side Error Message in Angular and .Net Core API

我有一些用 C# 编写的其余 API,并且该 API 是从 Angular 调用的(我使用的是 Angular 8 版本)。 通话很好,工作正常。 但是,如果出现任何异常,我无法以 angular 显示自定义错误消息。 例如,假设我在 C# 中有一个服务器端验证,它验证字段的值是否与字符串“abc”匹配。 如果不匹配,则会抛出错误,并且在 UI(用 Angular 开发)中,我想显示消息

“指定的字符串无效”。

我的服务器端代码如下 -

if (headerValues.Equals("abc")) {
    throw new InvalidStringException("Invalid String specified", 999);
}

Invalid InvalidStringException类如下 -

public class InvalidStringException : System.Exception
{
    int status { get; set; }
    public InvalidStringException() { }
    public InvalidStringException(string message, int status) : base(message) {
        this.status = status;
     }
}

当该异常被抛出并在服务器端捕获时,它可以作为 500 异常使用,但无法打印自定义消息。

我正在尝试在 Angular 中执行以下代码 -

} catch (error) {
  console.log("Error Status: ", error.status);
  console.log("Error Status: ", error.message);
}

请建议如何处理这种情况。

您的 Angular 应用程序收到的错误对象应该是HttpErrorResponse的实例

您可以执行以下操作来处理 http 错误:

if (error instanceof HttpErrorResponse) {
  if (!error.status) {
    console.log(error.message || error.toString());
  } else {
    console.log(`error status : ${error.status} ${error.statusText}`);
    switch (error.status) {
      case 401:
        this.router.navigateByUrl("/login");
        break;
      case 500:
        this.router.navigateByUrl("/login");
        console.log(`redirect to login`);
        break;
    }
  }
} else {
  console.error("Other Errors");
}

您是否在 .NET API 控制器中明确捕获InvalidStringException并返回自定义消息? 如果不是,则响应将是通用 HTTP 500“内部服务器错误”响应。 我建议在您的 .NET API 控制器中明确捕获InvalidStringException并使用您的自定义消息返回 400 响应,例如

try {
    ...
}
catch (InvalidStringException iex) {
    return BadRequest(iex.message); // iex.message == Invalid String specified
}

InvalidStringException情况发生时,这将返回一个 HTTP 400 响应,其中“指定了无效字符串”作为响应正文。 您应该能够像当前所做的那样在 Angular 端记录错误...

您正在抛出一个由 C# 异常处理程序处理的异常,它只会返回该处理程序中指定的自定义错误消息。

要返回自定义消息,您需要返回 4xx 或 5xx 等 http 代码。

new HttpResponseException(Request.CreateErrorResponse(System.Net.HttpStatusCode.Conflict, "Custom Message"));

或者你可以用 2xx 返回,你必须解析这个订阅或方法,例如

new System.Web.Http.Results.ResponseMessageResult(
                    Request.CreateResponse((HttpStatusCode)227, "Custom Error Message")
                );

this.http.get().toPromise().then((response: any) => {
        if (response.status == 227) {
            return error;
        } else {
            return data;
        }
        return apiResponse;
    }).catch(error => {
        //nothing here
    });

如果真的没有必要抛出异常,您可以使用BadRequest返回状态代码 400 和一条消息:

if (headerValues.Equals("abc")) {
    return BadRequest("Invalid String specified");
}

您可以使用http拦截器为angular应用程序中的所有http错误创建通用错误处理程序,这样您就可以使用警报,重定向到登录页面以防令牌过期,覆盖错误对象等等,但您仍然可以访问错误对象通过为可观察错误添加回调来提高组件级别。

错误处理服务

@Injectable()
export class ErrorHandlerService implements HttpInterceptor {
  constructor(private msgServ: MessageService) {}
  public intercept(
    req: HttpRequest<any>,
    next: HttpHandler
  ): Observable<HttpEvent<any>> {
    return next.handle(req).pipe(
      catchError((err: HttpErrorResponse) => {
        switch (err.status) {
          case 500: {
            this.msgServ.add({
              severity: "error",
              summary: "Error ",
              detail: "Server is gone..💀"
            });

            break;
          }
          case 400: {
            this.msgServ.add({
              severity: "error",
              summary: "Error ",
              detail: "custome error message..."
            });

            break;
          }
          case 401: {
            if (err.message == "invalid_token") {
              // router 👉 navigate to login
            }
            break;
          }

          default: {
            this.msgServ.add({
              severity: "error",
              summary: "Error ",
              detail: err.message
            });
          }
        }

        return throwError(err);
      })
    );
  }
}

将拦截器添加到应用程序模块中的提供者

@NgModule({
  ....
  providers: [
    { provide: HTTP_INTERCEPTORS, useClass: ErrorHandlerService, multi: true },
    MessageService
  ],
  ....
})
export class AppModule {}

演示🚀

MessageService与primeng 组件库相关,你可以使用你自己的alert 结构

正如其他人所提到的,您需要在自己的代码中捕获异常并将其转换为适当的 HTTP 响应。

这样做的原因是因为如果您的异常由 ASP.NET Core 使用您拥有的异常处理配置处理,并且它可能会有所不同:

带有开发者例外页面

通常在开发中,你会有代码:

if (env.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
}

它的作用是当您的环境为Development 时,它会打开一个特殊页面供开发人员查看未处理异常的信息。 只有在这种情况下,您才能在响应正文中获得异常堆栈跟踪以及异常消息。

无开发者异常页面

相反,如果关闭异常页面(通常在生产环境中关闭),您将在响应正文中看不到任何内容

怎么修

鉴于 ASP.NET Core 中的异常处理是一个跨领域的问题,我不会在任何需要将InvalidStringException转换为HttpResponse地方使用try...catch

我会改为使用IActionFilter或使用UseExceptionHandler ,它是异常处理中间件

以下是在Startup.cs 的Configure方法中使用UseExceptionHandler的示例:

app.UseExceptionHandler(opt => opt.Run(
    async ctx =>
    {
        var feature = ctx.Features.Get<IExceptionHandlerFeature>();
        if (feature.Error is InvalidStringException ex)
        {
            await ctx.Response.WriteAsync(ex.Message);
        }
    }));

这样,您的InvalidStringException在您的应用程序中全局处理,无需显式try...catch 您可以在代码中的任何位置抛出异常,上面的代码将捕获异常并将其正确转换为 HTTP 响应,并将您自己的消息作为正文。

另请注意,因为您是从 Angular 应用程序调用 API,所以如果这两个应用程序从不同的来源运行,您可能需要在 API 应用程序中设置 CORS

如果没有 CORS,来自 Angular 应用程序的 HTTP 请求可能会在到达您的 API 之前失败。 在这种情况下,您的 Angular 应用程序中 HTTP 响应的状态可能是undefined 在您的控制台中,您可以看到 CORS 错误。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM