(Angular)拦截HttpResponse错误并继续Observable



我有一个下拉文本框,可以进行预先键入搜索。当我搜索一个有效的项目名称(存在于数据库中(时,搜索工作正常,并在下拉列表中返回一个项目列表,以便在键入时从中进行选择。但是当我搜索无效文本时,API返回一个400错误(这很好(,然后HttpErrorInterceptorcatchError()方法中拦截该响应,并弹出一个错误弹出窗口。我不希望弹出错误,我希望它将错误转发到文本框逻辑,这样我就可以在下拉列表中显示"未找到项目"。

文本框html(使用Angular的NgbTypeahead(:

<input
id="searchText"
type="text"
[(ngModel)]="selectedItem"
(selectItem)="onSelectItem($event)"
formControlName="searchText"
[ngbTypeahead]="search"
#instance="ngbTypeahead" />

文本框逻辑:

search = (input: Observable<string>) => {
return input.pipe(
debounceTime(500),
distinctUntilChanged(),
switchMap((text) => text.length < 2 ? this.clearItems() //clearItems() is irrelavant
: this.itemService.getItemSearchData(text).pipe(
map(responseObj => {
const itemList = responseObj.data ? orderBy(responseObj.data, ['itemName'], ['asc']) : [];
if (itemList.length === 0) {
// this is what I want it to do when I get the error response
itemList.push({ itemName: 'No Items Found' } as ItemList);
}
return itemList;
})
)));
}
// This is in the ItemService class.
getItemSearchData(searchTerm: string): Observable<any> {
const searchItem = {
"filterBy": {
"key": "itemname",
"value": searchTerm
}
}

return this.http.post(this.itemApiUrl, searchItem, { headers: this.headers });
}

这就是拦截器:

@Injectable()
export class HttpErrorInterceptor implements HttpInterceptor {
constructor(private matDialog: MatDialog) { }

intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return next.handle(request)
.pipe(
catchError((error: HttpErrorResponse) => {
let errorMessage = 'Unknown error!';
if (error.error instanceof ErrorEvent) {
errorMessage = `Error: ${error.error.message}`;
} else {
errorMessage = `Error Code: ${error.status}nMessage: ${error.message}`;
}

// the error popup. I DON'T want to throw this when I get the 404 response.
this.matDialog.open(PopupComponent, {
data: { actionDesctiption: errorMessage, isError: true },
panelClass: 'custom-dialog-container'
});

return throwError(error);
})
);
}

我试过这样做:Angular:拦截HTTP错误并继续链,但顶级解决方案的return of(new HttpResponse...;语句给了我错误Type 'Observable<unknown>' is not assignable to type 'Observable<HttpEvent<any>>'。我还尝试返回next.handle(request)new Observable<HttpEvent<any>>()

当我在map(responseObj =>行放置断点时,它总是说";responseObj未定义";。

当API返回400错误时,如何使下拉列表显示"未找到项目"?

从API返回的数据的结构尚不清楚。假设API以以下格式返回数据:{ itemName: string }[](即{ itemName: string }对象的数组(,则可以使用http拦截器检查404错误,然后更改响应,如下所示:

import { HttpRequest, HttpResponse, HttpHandler, HttpEvent, HttpInterceptor } from '@angular/common/http';
import { HttpErrorResponse } from '@angular/common/http';
import { of, throwError } from 'rxjs';
@Injectable()
export class HttpErrorInterceptor implements HttpInterceptor {
constructor(private matDialog: MatDialog) { }

intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return next.handle(request)
.pipe(
catchError((error) => {
let errorMessage = 'Unknown error!';
if (error.error instanceof ErrorEvent) {
errorMessage = `Error: ${error.error.message}`;
} else {
errorMessage = `Error Code: ${error.status}nMessage: ${error.message}`;
}

// check for a 404 error response
if (error instanceof HttpErrorResponse && error.status === 404) {
return this.returnCustomData([{ itemName: 'No Items Found' }]); // returns a response, and doesn't throw the error
}

// the error popup. I DON'T want to throw this when I get the 404 response.
this.matDialog.open(PopupComponent, {
data: { actionDesctiption: errorMessage, isError: true },
panelClass: 'custom-dialog-container'
});
return throwError(error);
})
);
}
private returnCustomData(body) {
return of(new HttpResponse({ status: 200, body }));
}
}

注意:再次假设API返回一个{ itemName: string }对象数组,这就是为什么我在调用returnCustomData时在数组中使用一个对象。请记住更改发送到returnCustomData的数据对象,使其与API返回的实际数据格式相匹配,就好像它只返回了一个结果,其中包含"未找到项目"。

我知道您的拦截器可以处理任何请求的所有HTTP错误,但是,由于您在组件中需要该消息错误,不如在服务管道中添加catchError?

search = (input: Observable<string>) => {
return input.pipe(
debounceTime(500),
distinctUntilChanged(),
switchMap((text) => text.length < 2 ? this.clearItems() 
: this.itemService.getItemSearchData(text)
.pipe(
map(responseObj => {
const itemList = responseObj.data ? orderBy(responseObj.data, ['itemName'], ['asc']) : [];
return itemList;
}),
catchError(() => {
itemList.push({ itemName: 'No Items Found' } as ItemList));
of('');
}
)));
}

最新更新