我想知道可观察流中的错误处理。我阅读了有关在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'}
);
}
哪种解决方案更好?
答案 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请求。您无需注入错误管理服务。