角度6。 httpClient中错误处理的正确方法

时间:2018-08-26 21:45:05

标签: angular typescript error-handling rxjs

我想知道可观察流中的错误处理。我阅读了有关在Angular中使用rxjs和异步管道的文章。它写在这里,我们应该避免使用订阅运算符,并尝试将其替换为异步管道。但是现在,当我尝试编写一些发布/发布请求时,我们必须订阅,因此我在应该修改组件状态的地方有些困惑。

submitForm() {
  this.restService.add(this.user.id, this.form.value)
    .pipe(
      tap(() => { this.isAdded = true }),
      catchError((error: HttpErrorResponse) => {
          this.responseMsg = 'Something went wrong'
          return throwError('notFound')
        }
      )
    ).subscribe();
  }

或者我应该在订阅中处理

submitForm() {
      this.restService.add(this.user.id, this.form.value)
        .pipe(
          tap(() => { this.isAdded = true }),
        ).subscribe( 
            () => {}, 
            () => {this.responseMsg = 'Something went wrong'}
       );
 }

哪种解决方案更好?

3 个答案:

答案 0 :(得分:1)

这是正确使用异步管道的方式。当您使用异步管道时,您无需订阅,因为它们为您执行了可观察的生命周期。订阅并销毁订阅,以避免内存泄漏。如果您不使用异步管道,则必须手动执行。

SERVICE.TS

import { EquipmentID } from './../../../shared/model/equipmentID.model';
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import { PickupAvailability } from '../models/pickup-availability.model';
import { catchError } from 'rxjs/operators';
import { ErrorHandlingService } from '../../../shared/services/error-handling.service';
@Injectable()
export class PickupAvaibilityService {
  BASE_URL = '/sxrw-ship/api/v1';
  AMOUNT_DUE_URL = '/shipments/search';

  constructor(
    private http: HttpClient,
    private errorHandler: ErrorHandlingService
  ) {}

  getAmountDue(equipmentID: EquipmentID[]): Observable<PickupAvailability> {
    return this.http
      .post<PickupAvailability>(
        this.BASE_URL + this.AMOUNT_DUE_URL,
        equipmentID
      )
      .pipe(catchError(this.errorHandler.handleError));
  }
}

然后在我的自定义错误处理程序服务中,您将得到以下内容:

ERRORHANDLER.SERVICE.TS

import { Injectable } from '@angular/core';
import { HttpErrorResponse } from '@angular/common/http';
import { _throw } from 'rxjs/observable/throw';
@Injectable()
export class ErrorHandlingService {
  constructor() {}

  handleError(error: HttpErrorResponse) {
    //To know the version of RxJS npm list --depth=0 (I for this example im on version 5.5)
    if (error.error instanceof ErrorEvent) {
      // A client-side or network error occurred. Handle it accordingly.
      console.error('An error occurred: ', error.error.message);
    } else {
      // The backend returned an unsuccessful response code.
      // The response body may contain clues as to what went wrong,
      console.error(
        `Backend returned code ${error.status}` + ` body was: ${error.message}`
      );
    }
    // return an observable with a user-facing error message
    return _throw('Something bad happened; please try again later.');
  }
}

我执行错误处理程序的方式是在Angular的官方网站https://angular.io/guide/http

上完成的方式

现在,在将使用调用我们http的服务的组件中,您声明一个Observable类型的变量(使用$ sing是一个好习惯)

COMPONENT.TS

pickupAvailability$: Observable<PickupAvailability>;

  getPickupDate(pa: PickupAvailability) {
    let id = pa.equipmentInitial + pa.equipmentNumber;
    this.equipmentSummary$ = this.pickupDateService
      .getPickupDate(id)
      .pipe(
        map(
          pd =>
            new EquipmentSummary(
              id,
              pd.pickupDate,
              'TODO',
              pa.totalPremiseCharges
            )
        )
      );
  }

HTML

<div *ngIf="(pickupAvailability$ | async) as pickupAvailability">
  <!-- TODO move to table -->
  <div *ngFor="let pa of pickupAvailability">
    <button pButton type="button" label="Pay ${{ pa.totalPremiseCharges }}" class="x-primary-gray-100" (click)='getPickupDate(pa)'>
    </button>
  </div>
  <div *ngIf="(equipmentSummary$ | async) as es">
    <app-pay-storage [equipmentSummary]="es"></app-pay-storage>
  </div>
</div>

您可以通过以下方法进行测试:

{{pickupAvailability$ | async | json}}

当您实际使用它时,请删除json管道

答案 1 :(得分:0)

如果您只想处理来自后端API的错误(HTTP错误),则可以在订阅函数中处理它们。

您还可以使用自定义错误处理程序来处理所有HTTP错误:

import {ErrorHandler} from "@angular/core";
import {UNAUTHORIZED, BAD_REQUEST, FORBIDDEN} from "http-status-codes";
import {Router} from "@angular/router";
import {ToastsManager, Toast, ToastOptions} from "ng2-toastr";

@Injectable()
export class myAppErrorHandler implements ErrorHandler {

  static readonly REFRESH_PAGE_ON_TOAST_CLICK_MESSAGE: string = "An error occurred: Please click this message to refresh";
  static readonly DEFAULT_ERROR_TITLE: string = "Something went wrong";

  constructor(private router: Router,private toastManager: ToastsManager){};


  public handleError(error: any) {
    console.error(error);
    let httpErrorCode = error.httpErrorCode;
    switch (httpErrorCode) {
      case UNAUTHORIZED:
          this.router.navigateByUrl("/login");
          break;
      case FORBIDDEN:
          this.router.navigateByUrl("/unauthorized");
          break;
      case BAD_REQUEST:
         this.showError(error.message);
          break;
      default:
         this.showError(REFRESH_PAGE_ON_TOAST_CLICK_MESSAGE);
    }
  }

  private showError(message:string){
    this.toastManager.error(message, DEFAULT_ERROR_TITLE, { dismiss: 'controlled'}).then((toast:Toast)=>{
            let currentToastId:number = toast.id;
            this.toastManager.onClickToast().subscribe(clickedToast => {
                if (clickedToast.id === currentToastId) {
                    this.toastManager.dismissToast(toast);
                    window.location.reload();
                }
            });
        });
  }
}

然后告诉angular使用它而不是默认的错误处理程序,将其添加到app.module.ts中的provider部分中,如下所示:

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

答案 2 :(得分:0)

您可以考虑使用HttpClient interceptor

@Injectable()
export class HttpErrorInterceptor implements HttpInterceptor {
  constructor(public auth: AuthService) {}
  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {

       return next.handle(request)
            .pipe(catchError(err => {
                 // handle your logic there
             }));
   }
}

这样做,将在同一位置以相同方式处理所有Http请求。您无需注入错误管理服务。

更多信息在那里:Angular httpClient interceptor error handling