【问题标题】:Displaying Custom Server Side Error Message in Angular and .Net Core API在 Angular 和 .Net Core API 中显示自定义服务器端错误消息
【发布时间】:2020-07-01 12:28:19
【问题描述】:

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

“指定的字符串无效”。

我的服务器端代码如下 -

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

无效的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);
}

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

【问题讨论】:

  • 您是否尝试过调试并查看带有错误参数的 catch 块中的属性?它可能具有与简单的“状态”或“消息”不同的属性名称 catch 块中“错误”的属性和属性是什么?
  • 你在前端有什么? catch 块会捕获错误吗? error中放置了什么对象?
  • 也尝试返回异常而不是抛出可能吗?
  • 您能否在调试器的网络选项卡中显示该请求的响应内容?
  • 你能展示你如何从 Angular 调用你的 API 吗?您只在问题中包含了catch 部分。

标签: c# angular rest .net-core


【解决方案1】:

你的 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");
}

【讨论】:

    【解决方案2】:

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

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

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

    或者你可以返回 2xx 并且你必须解析这个 subscribe 或者 then 方法,例如

    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
        });
    

    【讨论】:

      【解决方案3】:

      如果不是真的需要抛出异常,可以返回状态码 400 和使用BadRequest 的消息:

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

      【讨论】:

        【解决方案4】:

        您是否在 .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 端记录错误,就像您目前正在做的那样......

        【讨论】:

        • 谢谢兄弟......似乎它工作正常并显示预期的消息。
        【解决方案5】:

        您可以使用 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 {}
        

        demo ?

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

        【讨论】:

        • 我对don net不熟悉,所以我对前端部分的回答??
        【解决方案6】:

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

        这样做的原因是,否则,您的异常由 ASP.NET Core 使用 exception handling configuration 处理,并且可能会有所不同:

        有开发者例外页面

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

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

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

        无开发者异常页面

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

        如何解决

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

        我会改用an IActionFilter or use UseExceptionHandler which is the exception handling middleware:

        这是一个在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 应用程序中使用 set CORS up

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

        【讨论】:

          猜你喜欢
          • 2020-09-17
          • 1970-01-01
          • 2018-10-18
          • 1970-01-01
          • 2018-12-04
          • 1970-01-01
          • 2020-06-22
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多