【问题标题】:HttpInterceptor in Angular 4.3: Intercepting 400 error responsesAngular 4.3 中的 HttpInterceptor:拦截 400 错误响应
【发布时间】:2018-01-04 03:49:05
【问题描述】:

我想拦截 401 和其他错误,以便做出相应反应。这是我的拦截器:

import { LoggingService } from './../logging/logging.service';
import { Injectable } from '@angular/core';
import { HttpInterceptor, HttpHandler, HttpRequest, HttpEvent, HttpResponse, HttpErrorResponse } from '@angular/common/http';

import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/do';

@Injectable()
export class TwsHttpInterceptor implements HttpInterceptor {

    constructor(private logger: LoggingService) { }

    intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        this.logger.logDebug(request);    
        return next.handle(request)
            .do(event => {
                if (event instanceof HttpResponse) {
                    this.logger.logDebug(event);
                }
            });
    }
}

虽然这适用于 200 个请求,但 它不会拦截错误响应

我在 chrome 的开发控制台中看到的是这样的:

zone.js:2616 GET http://localhost:8080/backend/rest/wrongurl 404(不是 找到)

或者这个

zone.js:2616 获取http://localhost:8080/backend/rest/url 401 (未经授权)

我希望我的拦截器处理这个问题。我错过了什么?

【问题讨论】:

    标签: angular interceptor


    【解决方案1】:

    Http 将错误发送到 observable 的错误流中,因此您需要使用 .catch 捕获它们(您可以阅读有关此here 的更多信息)。

    return next.handle(request)
      .do(event => {
        if (event instanceof HttpResponse) {
          this.logger.logDebug(event);
        }
      })
      .catch(err => { 
        console.log('Caught error', err);
        return Observable.throw(err);
      });
    

    【讨论】:

    • 好的,但这给了我这个错误:[ts] '(err: any) => void' 类型的参数不可分配给'(err: any,caught: Observable>) => ObservableInput'。类型“void”不可分配给类型“ObservableInput”。
    • 添加“return Observable.throw(err);”解决问题。编辑你的答案,我会接受的!
    • @Tim 这样吗?抱歉,我在发布之前没有对其进行测试:)
    • @Tim 代码格式在 cmets 中也可以使用 `` 语法
    • 对于 rxjs 6 世界:return next.handle(request) .pipe( tap(event => console.log(event)), catchError(err => throwError(err)), );
    【解决方案2】:

    这对你来说可能已经太晚了,但希望其他人会发现它有用......这也是如何重写上面的返回语句以记录错误响应:

    return next.handle(request).do((event: HttpEvent<any>) => {
      if (event instanceof HttpResponse) {
        this.logger.logDebug(event);
      }
    }, (error: any) => {
      if (error instanceof HttpErrorResponse) {
        this.logger.logDebug(error);
      }
    });
    

    我正在使用相同的方法自动将所有 401 Unauthorized 响应直接发送到我们的注销方法(而不是在每次单独调用 http 时检查 401):

    return next.handle(request).do((event: HttpEvent<any>) => {
      if (event instanceof HttpResponse) {
        // process successful responses here
      }
    }, (error: any) => {
      if (error instanceof HttpErrorResponse) {
        if (error.status === 401) {
          authService.logout();
        }
      }
    });
    

    它就像一个绝对的魅力。 :)

    【讨论】:

    • 如果发生错误我想记录错误但仍返回 HttpResponse 以便 Angular 客户端可以在 UI 上显示错误消息怎么办?
    • 如果您在问题中指的是“HttpErrorResponse”(而不是 HttpResponse),那么我的回复中的第一个示例正好说明了这一点。成功响应和错误响应都被记录下来,然后像根本没有拦截器一样继续传递。
    【解决方案3】:

    为了拦截 Angular 6 中的 Http 响应错误,我做了一个小技巧,将 Observable 转换为 Promise:

    intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
       const obs = next.handle(req);
    
       if (!window.navigator.onLine) {
         // Handle offline error
         this.messageService.showError('No Internet Connection');
         return;
       }
    
       obs.toPromise().catch((error) => {
         this.messageService.progress(false);
         this.messageService.showError(error.message);
       });
       return obs;
    }
    

    【讨论】:

      【解决方案4】:

      当时我正在尝试 Angular 7+

      不幸的是上述解决方案不能很好地完成这项工作,因为 .do 在 RxJs 6 管道概念中不能直接在 HttpHandler 上使用;并且转换 Observable to Promise 不会坚持。

      这是干净且最新的方法;我pipecatchError 运算符并分析错误,最后使用throwError 重新抛出它。这是拦截器的最终形状;

        intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
          return next.handle(req).pipe(
            catchError((error: HttpErrorResponse) => {
              if (error.error instanceof ErrorEvent) {
                // client-side error or network error
      
              } else {
                // TODO: Clean up following by introducing method
                if (error.status === 498) { 
                  // TODO: Destroy local session; redirect to /login
                }
                if (error.status === 401) { 
                  // TODO: Permission denied; show toast
                }
              }
              return throwError(error);
            })
          );
        }
      

      希望这个解决方案将来能对某人有所帮助。

      【讨论】:

        猜你喜欢
        • 2018-01-12
        • 1970-01-01
        • 2018-02-20
        • 2021-02-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-02-13
        • 2018-01-07
        相关资源
        最近更新 更多