Angular HttpStatus 4xx | 5xx 拦截器(条件性)

huangapple go评论65阅读模式
英文:

Angular HttpStatus 4xx | 5xx Interceptor (conditional)

问题

在Angular v.11(也适用于v.13)中,我需要编写一个拦截器,以在后端请求返回错误(状态码为4xx或5xx)时向用户显示错误文本消息。

我知道在Angular中编写Http拦截器来处理这种情况是可能的,但我有一个特殊情况,我必须仅在没有明确处理http错误的情况下拦截并显示错误文本消息。

示例代码:

情况1:

this.http.get().subscribe(
   success(data),
   error(err)
);

情况2:

this.http.get().subscribe(
   success(data)
);

为了澄清,我需要仅在没有定义error(err)处理函数的情况下显示错误文本消息(就像在情况2中一样)。

我不确定如何做到这一点,也不确定是否可能,但我认为应该有一个简单的解决方案来解决这个问题,我自己找不到。

英文:

In an Angular v.11 (also v.13 ) I need to write an Interceptor to show an error-text message to the user when the backend request return an error (status code 4xx or 5xx).

I know it is possible in Angular to write HttpInterceptors for this case, but I have a special case, where I must intercept and show the error-text message only if no explicit handlig for http-errors specified.

ex. code:

Case-1:

this.http.get().subscribe(
   success(data),
   error(err)
);

Case-2:

this.http.get().subscribe(
   success(data)
);

For clarification, I need to show the error-text message only if there is no error(err) handling function defined (like in Case-2).

Im not sure how to do that, and I am not sure if that is possible, but I think there should be a simple solution to that problem, that I cannot find by myself.

答案1

得分: 1

听起来像是只有在没有本地错误处理时才会应用的全局错误处理。说实话,这不是我会选择的架构类型。

全局错误处理在某种程度上需要知道何时根据提供的参数或其他全局服务来应用其处理(即本地错误处理需要通知一个服务)。

我无法评判你可以改变多少错误处理,但全局错误处理应处理适用于绝大多数,如果不是所有HTTP请求的通用错误。而本地错误处理将处理特定于该特定请求的特定情况。

这样你可以同时运行两个错误处理程序,而不会互相干扰。

由于你的问题似乎与用户界面相关(即显示错误消息),上述方法也将涵盖这一点。全局错误处理将显示某种通用错误消息,同时你可以为本地处理程序添加额外的错误消息。我想两者都会利用相同的服务来显示错误消息。

英文:

Sounds like global error handling that is only applied if there's no local error handling. It isn't exactly the type of architecture I'd go for, tbh.

The global error handling would somehow need to know when to apply its handling based on provided parameters or some other global service it could check (ie. local error handling would need to notify a service).

I can't judge how much of your error handling you can change, but global error handling should handle generic errors that apply to a majority if not all HTTP requests. While the local one would handle specific cases exclusive to that particular request.
That way you could run both error handlers without the risk of them interfering with each other.

Since your problem seems to be UI related (ie. displaying error msg), the above approach would cover that as well. Global error handling would display some sort of generic error msg while you could add an additional error msg for your local handler. Both would be utilizing the same service for displaying error messages, I suppose.

答案2

得分: 1

你可以在使用 HttpClient 时向头部添加一个简单的标志,然后在 HTTP_INTERCEPTORS 中检查是否存在此标志,以决定是否处理它!

例如:

//在组件或服务文件中: -

this.http.get(
'https://jsonplaceholder.typicode.com/todos/2',
{ headers: {'byPass': 'yes'} })
.subscribe((response: any) => {
console.log(response);
}
);

//在拦截器中: -

public intercept(req: HttpRequest, next: HttpHandler): Observable<HttpEvent> {
//如果有 byPass 头部,则不处理错误并在此处删除此标志
if (req.headers.has('byPass')) {
const newHeaders = req.headers.delete('byPass')
const newRequest = req.clone({ headers: newHeaders });
return next.handle(newRequest);
} else {
//根据需要处理错误
return next.handle(req);
}
}

但你仍然应该在拦截器中编写一个通用的错误处理程序。

英文:

You can add a simple flag to the header when using HttpClient, then in the HTTP_INTERCEPTORS, you can check if this flag is existing, to decide to handle it or not!

For e.g. :-

//In component or service file: -

this.http.get(
  &#39;https://jsonplaceholder.typicode.com/todos/2&#39;,
  { headers: {&#39;byPass&#39;: &#39;yes&#39;} })
  .subscribe((response: any) =&gt; {
    console.log(response);
  }
);

//In interceptor: -

public intercept(req: HttpRequest&lt;any&gt;, next: HttpHandler): Observable&lt;HttpEvent&lt;any&gt;&gt; {
    // if there is byPass header, don&#39;t handle the error and remove this flag here
    if (req.headers.has(&#39;byPass&#39;)) {
        const newHeaders = req.headers.delete(&#39;byPass&#39;)
        const newRequest = req.clone({ headers: newHeaders });
        return next.handle(newRequest);
    } else {
        //Handle the error accordingly
        return next.handle(req);
    }
}

Still you should write a generic Error handler in interceptor only.

答案3

得分: 0

忽略是否是一个好方法,专注于可行性。我们的目标是只在没有提供其他错误处理时才启动通用处理程序。

首先让我们更好地了解可用于我们的工具,HttpClientHttpInterceptor

  • HttpClient 方法:根据提供的选项和方法创建一个 HttpRequest,尝试解析它并返回一个 Observable
  • HttpInterceptor:它接收一个 HttpRequest,并基于它执行某些操作。它必须返回一个 Observable&lt;HttpEvent&lt;any&gt;&gt;

我们的两个元素之间只有一个连接点,那就是用于创建 HttpRequest 的选项,该请求将被我们的 HttpInterceptor 使用。
因此,我们无法访问 .subscribe() 来检查是否存在错误处理回调。

简而言之,仅通过添加错误处理回调,在提供的限制下无法实现你所要求的

然后问题出现了,如果我们以某种方式放宽了我们的限制,我们能否实现它呢?
答案在于我们传递给 HttpClient 方法的选项。

我们可以向我们的拦截器传递一个唯一的参数,并使用它来检查是否需要全局错误处理程序,如下所示:

  withGlobalError(): void {
    this.httpClient.get('www.foo.com', { params: { globalError: true } }).subscribe(
      _ => console.log('success')
    );
  }

  withoutGlobalError(): void {
    this.httpClient.get('www.foo.com').subscribe(
      _ => console.log('success'),
      error => console.log('本地范围内的错误处理程序', error)
    );
  }

在我们的 HttpInterceptor 中,我们需要检查参数 globalError 是否存在并且为 true。如果是,我们可以执行我们需要的操作。

  intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
    return next.handle(request).pipe(catchError(error => {
      if (request.params.get('globalError')) {
        console.log('在全局拦截器中处理错误');
      }
      return throwError(error);
    }))
  }

这是实现你想要的最简单方法。它允许存在全局错误处理,同时又确保每个开发人员都知道何时会触发它。

英文:

Ignoring if its a good approach or not and focusing on the feasibility.
Our goal is to only launch a generic handler when no other error handling is provided.

First let us understand better the tools to available to us, the HttpClient and the HttpInterceptor.

  • HttpClient methods: create a HttpRequest based on the provided options and methods, attempts to resolve it and returns an Observable.
  • HttpInterceptor: it receives an HttpRequest and based on it performs something. It must return an Observable&lt;HttpEvent&lt;any&gt;&gt;.

There is only one point connecting our 2 elements, the options that are used to create the HttpRequest that will be used by our HttpInterceptor.
Therefor, we cannot access the .subscribe() to check if there is an error handling callback or not.

In short, with just adding the error handling callback, it is not possible to perform what you are asking with the provided restrictions.

The question then arrises, can we achieve it if we somehow lax our restrictions?
Well the answer lies in the options we pass to our HttpClient method.

We could pass an unique param to our interceptor, and use it to check if it needs the global error handler or not, like so:

  withGlobalError(): void {
    this.httpClient.get(&#39;www.foo.com&#39;, { params: { globalError: true } }).subscribe(
      _ =&gt; console.log(&#39;success&#39;)
    );
  }

  withoutGlobalError(): void {
    this.httpClient.get(&#39;www.foo.com&#39;).subscribe(
      _ =&gt; console.log(&#39;success&#39;),
      error =&gt; console.log(&#39;Error handler in local scope&#39;, error)
    );
  }

In our HttpInterceptor we need to check if the param globalError exists and is true. When so we can perform whatever we need.

  intercept(request: HttpRequest&lt;unknown&gt;, next: HttpHandler): Observable&lt;HttpEvent&lt;unknown&gt;&gt; {
    return next.handle(request).pipe(catchError(error =&gt; {
      if (request.params.get(&#39;globalError&#39;)) {
        console.log(&#39;Handling error in the Global Interceptor&#39;);
      }
      return throwError(error);
    }))
  }

This is the simplest approach to achieve what you want. It allows for global error handling to exist, while at the same time ensuring that every developer is aware of when it will be triggered.

huangapple
  • 本文由 发表于 2023年1月9日 17:34:42
  • 转载请务必保留本文链接:https://go.coder-hub.com/75055362.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定