如何将异步错误处理放入单独的函数中?

时间:2019-05-27 23:42:21

标签: angular typescript ionic4

我想将以下示例中显示的错误处理放到一个函数中:

import { Injectable } from '@angular/core';
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent } from '@angular/common/http';
import { Observable } from 'rxjs';
import { AuthService } from '../auth/auth.service';
import { tap, flatMap, concatMap } from 'rxjs/operators';
import { AlertController } from '@ionic/angular';

@Injectable()
export class ApiInterceptor implements HttpInterceptor {

    constructor(private auth: AuthService, private alertCon: AlertController) { }

    errorCodeToMessage = {
        500: "Internal server error has occurred. Please contact support.",
        404: "This resource can not be found. Please contact support.",
        403: "Access denied. Are you logged in?"
    };

    intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        if(req.url != this.auth.LOGIN_URL && req.url != this.auth.REGISTRATION_URL)
            return this.auth.getToken()
            .pipe(
                concatMap((token: string) => {
                        req = req.clone({
                            setHeaders: {
                                'authorization': token
                            }
                        });
                    // Also handle errors globally
                    return next.handle(req).pipe(
                        tap(x => x, 
                            async (error) => {
                            const alert = await this.alertCon.create({
                                header: 'Error',
                                subHeader: null,
                                message: this.errorCodeToMessage[error.status],
                                buttons: ['OK']
                              });

                            await alert.present();
                        }
                        )
                    );
                }))
                ;
        else
            return next.handle(req).pipe(
                        tap(x => x, async (error) => {
                            console.log("the error is: ");
                            console.log(error);
                            const alert = await this.alertCon.create({
                                header: 'Error',
                                subHeader: null,
                                message: this.errorCodeToMessage[error.status],
                                buttons: ['OK']
                              });

                            await alert.present();
                        })
                    );
    }

}

但是,当我这样做时,注入的AlertController似乎不再可用。

import { Injectable } from '@angular/core';
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent } from '@angular/common/http';
import { Observable } from 'rxjs';
import { AuthService } from '../auth/auth.service';
import { tap, flatMap, concatMap } from 'rxjs/operators';
import { AlertController } from '@ionic/angular';

@Injectable()
export class ApiInterceptor implements HttpInterceptor {

    constructor(private auth: AuthService, private alertCon: AlertController) { }

    errorCodeToMessage = {
        500: "Internal server error has occurred. Please contact support.",
        404: "This resource can not be found. Please contact support.",
        403: "Access denied. Are you logged in?"
    };


    async handleError(error) {
        console.log(error);
        const alert = await this.alertCon.create({
            header: 'Error',
            subHeader: null,
            message: this.errorCodeToMessage[error.status],
            buttons: ['OK']
          });

        await alert.present();
    }

    intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        if(req.url != this.auth.LOGIN_URL && req.url != this.auth.REGISTRATION_URL)
            return this.auth.getToken()
            .pipe(
                concatMap((token: string) => {
                        req = req.clone({
                            setHeaders: {
                                'authorization': token
                            }
                        });
                    // Also handle errors globally
                    return next.handle(req).pipe(
                        tap(x => x, this.handleError)
                    );
                }))
                ;
        else
            return next.handle(req).pipe(
                        tap(x => x, this.handleError)
                    );
    }

}

运行时错误:

    ERROR Error: Uncaught (in promise): TypeError: Cannot read property 'create' of undefined
TypeError: Cannot read property 'create' of undefined
    at TapSubscriber.<anonymous> (api.interceptor.ts:23)
    at step (tslib.es6.js:97)
    at Object.next (tslib.es6.js:78)
    at tslib.es6.js:71
    at new ZoneAwarePromise (zone.js:910)
    at Module.__awaiter (tslib.es6.js:67)
    at TapSubscriber.push../src/app/api/api.interceptor.ts.ApiInterceptor.handleError [as _tapError] (api.interceptor.ts:21)
    at TapSubscriber.push../node_modules/rxjs/_esm5/internal/operators/tap.js.TapSubscriber._error (tap.js:55)
    at TapSubscriber.push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber.error (Subscriber.js:60)
    at XMLHttpRequest.onLoad (http.js:1640)
    at resolvePromise (zone.js:831)
    at new ZoneAwarePromise (zone.js:913)
    at Module.__awaiter (tslib.es6.js:67)
    at TapSubscriber.push../src/app/api/api.interceptor.ts.ApiInterceptor.handleError [as _tapError] (api.interceptor.ts:21)
    at TapSubscriber.push../node_modules/rxjs/_esm5/internal/operators/tap.js.TapSubscriber._error (tap.js:55)
    at TapSubscriber.push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber.error (Subscriber.js:60)
    at XMLHttpRequest.onLoad (http.js:1640)
    at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:423)
    at Object.onInvokeTask (core.js:17290)
    at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:422)

我猜测这与不在闭包中有关,但我可能是错的。为什么会发生这种情况?我该怎么办才能让一个函数执行错误处理?

3 个答案:

答案 0 :(得分:2)

如果使errorHandler成为箭头函数,则它应该包装this上下文,并允许您在拦截方法内部访问注入的AlertController。

handleError = async (error: any) => {
    console.log(error);
    const alert = await this.alertCon.create({
        header: 'Error',
        subHeader: null,
        message: this.errorCodeToMessage[error.status],
        buttons: ['OK']
      });

    await alert.present();
}

答案 1 :(得分:1)

您可以使用全局错误处理程序

首先,让我们定义一个将从

继承的GlobalErrorHandler类。
Kotlin

现在在我们的模块中,我们必须告诉Angular使用我们的import { ErrorHandler, Injectable} from '@angular/core'; @Injectable() export class GlobalErrorHandler implements ErrorHandler { constructor() { } handleError(error) { console.log('Error Occured') // IMPORTANT: Rethrow the error otherwise it gets swallowed throw error; } } 而不是像下面这样的默认值:

GlobalErrorHandler

答案 2 :(得分:0)

在代码中进行更改。

  • 不可变逻辑,用于更新请求标头。使用相同的逻辑 也更新参数。

  • 而不是tap运算符,请使用catchError运算符。

intercept(
    req: HttpRequest<any>,
    next: HttpHandler
  ): Observable<HttpEvent<any>> {
    if (
      req.url !== this.auth.LOGIN_URL &&
      req.url !== this.auth.REGISTRATION_URL
    ) {
      return this.auth.getToken().pipe(
        concatMap((token: string) => {
          const updatedReq = req.clone({
            headers: req.headers.set('authorization', token)
          });
          // Also handle errors globally
          return next.handle(updatedReq).pipe(catchError(this.handleError));
        })
      );
    } else {
      return next.handle(req).pipe(catchError(this.handleError));
    }
  }

 handleError(err): Observable<any> {
    // error logs updation logics here.
    return throwError(err);
  }