(Angular) 拦截 HttpResponse 错误并继续 Observable
(Angular) Intercept HttpResponse error and continue the Observable
我有一个下拉文本框可以进行预输入搜索。当我搜索一个有效的项目名称(存在于数据库中)时,搜索工作正常并且 returns 下拉列表中的项目列表从我键入的 select 。但是当我搜索无效文本时,API returns 出现 400 错误(这很好),然后 HttpErrorInterceptor
在 catchError()
方法中拦截该响应,并抛出错误弹出窗口。我不想要错误弹出窗口,我希望它将错误转发给文本框逻辑,这样我就可以在下拉列表中显示 'No Items Found'。
文本框 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);
})
);
}
我试过这个:,但是顶级解决方案的 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 returns 400 错误时,如何让下拉菜单显示 'No Items Found'?
不清楚从您的 API 返回的数据结构是什么。假设 API returns 这种格式的数据:{ 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 returns 是一个 { itemName: string }
对象数组,这就是我使用一个对象的原因调用时数组中的对象 returnCustomData
。请记住更改发送到 returnCustomData
的数据对象以匹配您的 API 返回的实际数据格式,就好像它只返回一个结果,包含单词 'No Items Found'.
我知道您的拦截器可以处理任何请求的所有 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('');
}
)));
}
我有一个下拉文本框可以进行预输入搜索。当我搜索一个有效的项目名称(存在于数据库中)时,搜索工作正常并且 returns 下拉列表中的项目列表从我键入的 select 。但是当我搜索无效文本时,API returns 出现 400 错误(这很好),然后 HttpErrorInterceptor
在 catchError()
方法中拦截该响应,并抛出错误弹出窗口。我不想要错误弹出窗口,我希望它将错误转发给文本框逻辑,这样我就可以在下拉列表中显示 'No Items Found'。
文本框 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);
})
);
}
我试过这个: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 returns 400 错误时,如何让下拉菜单显示 'No Items Found'?
不清楚从您的 API 返回的数据结构是什么。假设 API returns 这种格式的数据:{ 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 returns 是一个 { itemName: string }
对象数组,这就是我使用一个对象的原因调用时数组中的对象 returnCustomData
。请记住更改发送到 returnCustomData
的数据对象以匹配您的 API 返回的实际数据格式,就好像它只返回一个结果,包含单词 'No Items Found'.
我知道您的拦截器可以处理任何请求的所有 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('');
}
)));
}