web-dev-qa-db-ja.com

Angular 6のHTTPエラー処理

私は、angular 6.の以下のクラスを使用してhttpエラーを処理しようとしています。サーバーから401未認証ステータスを取得しました。ただし、コンソールエラーメッセージは表示されません。

HttpErrorsHandler.tsファイル

import { ErrorHandler, Injectable} from '@angular/core';
    @Injectable()
    export class HttpErrorsHandler implements ErrorHandler {
      handleError(error: Error) {
         // Do whatever you like with the error (send it to the server?)
         // And log it to the console
         console.error('It happens: ', error);
      }
    }

http error

app.module.tsファイル

providers: [{provide: ErrorHandler, useClass: HttpErrorsHandler}],

HttpCallFile

import { Injectable , Component} from '@angular/core';
import { HttpClient, HttpHeaders } from "@angular/common/http";
import { Observable } from 'rxjs';
import {AuthServiceJwt} from '../Common/sevice.auth.component';

@Injectable()
export class GenericHttpClientService {
    private readonly baseUrl : string = "**********";


    constructor(private httpClientModule: HttpClient , private authServiceJwt : AuthServiceJwt)  {
    }

    public GenericHttpPost<T>(_postViewModel: T , destinationUrl : string): Observable<T> {
        const headers = new HttpHeaders().set('Content-Type', 'application/json; charset=utf-8')
            .set('Authorization',`Bearer ${this.authServiceJwt.getToken}`);
        return this.httpClientModule.post<T>(this.baseUrl + destinationUrl, _postViewModel, { headers });
    }

    // This method is to post Data and Get Response Data in two different type
    public GenericHttpPostAndResponse<T,TE>(postViewModel: TE, destinationUrl: string): Observable<T> {
        const headers = new HttpHeaders().set('Content-Type', 'application/json; charset=utf-8')
            .set('Authorization',`Bearer ${this.authServiceJwt.getToken}`);
        return this.httpClientModule.post<T>(this.baseUrl + destinationUrl, postViewModel, { headers });
    }

    // This method is to post Data and Get Response Data in two different type without JWT Token
    public GenericHttpPostWithOutToken<T,TE>(postViewModel: TE, destinationUrl: string): Observable<T> {
        const headers = new HttpHeaders().set('Content-Type', 'application/json; charset=utf-8');
        return this.httpClientModule.post<T>(this.baseUrl + destinationUrl, postViewModel, { headers });
    }

    public GenericHttpGet<T>(destinationUrl: string): Observable<T> {
        const headers = new HttpHeaders().set('Content-Type', 'application/json')
            .set('Authorization',`Bearer ${this.authServiceJwt.getToken}`);
        return this.httpClientModule.get<T>(this.baseUrl + destinationUrl, { headers });
    }

    public GenericHttpDelete<T>(destinationUrl: string): Observable<T> {
        const headers = new HttpHeaders().set('Content-Type', 'application/json')
            .set('Authorization',`Bearer ${this.authServiceJwt.getToken}`);
        return this.httpClientModule.delete<T>(this.baseUrl + destinationUrl, { headers });
    }
}

admin.user.component.tsファイル

private getUsersHttpCall(): void {
    this.spinnerProgress = true;
    this.genericHttpService.GenericHttpGet<GenericResponseObject<UserViewModel[]>>(this.getAdminUserUrl).subscribe(data => {
      if (data.isSuccess) {
        this.genericResponseObject.data = data.data;
        this.dataSource = this.genericResponseObject.data
        this.spinnerProgress = false;
      }

    }, error => {
      console.log(error);
      this.spinnerProgress = false;
    });
  }
23
San Jaisy

XHRリクエストには、Interceptorを使用する必要があります

これは、ヘッダーにJWTを追加し、いくつかの応答エラーを処理するために使用するものです。

import {Injectable} from '@angular/core';
import {
  HttpRequest,
  HttpHandler,
  HttpEvent,
  HttpInterceptor, HttpErrorResponse
} from '@angular/common/http';
import {AuthService} from '../service/auth.service';
import {Observable, of} from 'rxjs';
import {Router} from "@angular/router";
import {catchError} from "rxjs/internal/operators";

@Injectable()
export class TokenInterceptor implements HttpInterceptor {

  constructor(public auth: AuthService, private router: Router) {
  }


  /**
   * intercept all XHR request
   * @param request
   * @param next
   * @returns {Observable<A>}
   */
  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {

    if (localStorage.getItem('jwtToken')) {
      request = request.clone({
        setHeaders: {
          Authorization: 'Bearer ' + localStorage.getItem('jwtToken')
        }
      });
    }

    /**
     * continues request execution
     */
    return next.handle(request).pipe(catchError((error, caught) => {
        //intercept the respons error and displace it to the console
        console.log(error);
        this.handleAuthError(error);
        return of(error);
      }) as any);
  }


  /**
   * manage errors
   * @param err
   * @returns {any}
   */
  private handleAuthError(err: HttpErrorResponse): Observable<any> {
    //handle your auth error or rethrow
    if (err.status === 401) {
      //navigate /delete cookies or whatever
      console.log('handled error ' + err.status);
      this.router.navigate([`/login`]);
      // if you've caught / handled the error, you don't want to rethrow it unless you also want downstream consumers to have to handle it as well.
      return of(err.message);
    }
    throw err;
  }
}

インターセプターをapp.module.tsに登録することを忘れないでください:

import { TokenInterceptor } from './auth/token.interceptor';

@NgModule({
  declarations: [],
  imports: [],
  exports: [],
  providers: [
    {
      provide: HTTP_INTERCEPTORS,
      useClass: TokenInterceptor,
      multi: true,
    }
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }
35
firegloves

@fireglovesの答えから、個々のサービスの.pipeハンドラーが実際にcatchError独自のHTTP障害コードを使用できるようにするには、次のようにコードを構成する必要があります。

  1. インターセプターがHTTP 401エラーコードを検出した場合、それを処理し、of(error)を返します。これは、後続の.pipeで通常処理される可能性があります。
  2. HTTPエラーコードがInterceptorが処理するように設計されていない場合、throwを再度処理するので、サービス内のエラーハンドラーのように、後続のエラーハンドラーが独自の呼び出しで401以外のエラーをピックアップして処理できます。

インターセプターには2つの仕事があります。それ:

  1. トークンが保存されている場合、すべての発信要求にAuthorizationヘッダーを挿入します。
  2. HTTP 401認証されていないエラーをインターセプトします。この時点で、トークンストアが無効になり、/loginにリダイレクトされます。
import { Injectable } from '@angular/core';
import { Router } from '@angular/router';
import {
    HttpErrorResponse,
    HttpEvent,
    HttpHandler,
    HttpInterceptor,
    HttpRequest,
} from '@angular/common/http';
import { Observable } from 'rxjs';
import { catchError } from 'rxjs/operators';
import { of } from 'rxjs/observable/of';

import { AuthService } from './auth.service';

@Injectable({
    providedIn: 'root',
})
export class RequestInterceptor implements HttpInterceptor {

    constructor(
        private readonly auth: AuthService,
        private readonly router: Router,
    ) {
    }

    /**
     * @param HttpRequest<any> request - The intercepted request
     * @param HttpHandler next - The next interceptor in the pipeline
     * @return Observable<HttpEvent<any>>
     */
    intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        request = this.addToken(request);
        return next.handle(request)
            // add error handling
            .pipe(
                catchError(
                    (error: any, caught: Observable<HttpEvent<any>>) => {
                        if (error.status === 401) {
                            this.handleAuthError();
                            // if you've caught / handled the error, you don't
                            // want to rethrow it unless you also want
                            // downstream consumers to have to handle it as
                            // well.
                            return of(error);
                        }
                        throw error;
                    }
                ),
            );
    }

    /**
     * Handle API authentication errors.
     */
    private handleAuthError() {
        // clear stored credentials; they're invalid
        this.auth.credentials = null;
        // navigate back to the login page
        this.router.navigate(['/login']);
    }

    /**
     * Add stored auth token to request headers.
     * @param HttpRequest<any> request - the intercepted request
     * @return HttpRequest<any> - the modified request
     */
    private addToken(request: HttpRequest<any>): HttpRequest<any> {
        const token: string = this.auth.token;
        if (token) {
            return request.clone({
                setHeaders: {
                    Authorization: `Bearer ${token}`,
                },
            });
        }
        return request;
    }

}

AuthServiceには、クレデンシャルオブジェクトをlocalStorageに固定するパブリックget/setがあります-トークンが期限切れにならないようにしますが、必要に応じて設計できます。

上記の@fireglovesと同様に、インターセプターをapp.module.tsのパイプラインに追加する必要があります。

import { RequestInterceptor } from './auth/request.interceptor';

@NgModule({
    declarations: [],
    imports: [],
    exports: [],
    providers: [
        {
            provide: HTTP_INTERCEPTORS,
            useClass: RequestInterceptor,
            multi: true,
        },
    ],
    bootstrap: [AppComponent],
})
export class AppModule { }
9
amphetamachine

サンプルエラーハンドラインangular 7

public getstats(param: string, confgId: number, startDate: Date, endDate: Date): Observable<string> {
return this.http.post(this.stats, {
  param: param,
  endDate: endDate
}).pipe(tap((stats: string) => console.log('Got Exceedance Stats : ' + JSON.stringify(stats))),
  catchError(this.handleError<string>('stats')));

}

以下はエラーハンドラです

private handleError<T>(operation = 'operation', result?: T) {
return (error: any): Observable<T> => {
  console.error(error);   
  console.log(`${operation} failed: ${error.message}`);
  return of(result as T);
};

}

ここにコードを入力してください

1
ranki