HttpInterceptor - 希望服务器响应在某些错误情况下流向我的组件
HttpInterceptor - want server responses to flow to my component for certain error conditions
我希望响应正文中的错误响应从我的 API 服务器一直流到我的组件以获得某些错误代码,例如 400 或 422。它在没有 HttpInterceptor 的情况下运行良好下面的实现。
function handleHttpError() {
return (response: any) => {
let newResponse;
if (response.status === 0) {
// Error connecting to the server
newResponse = { error: 'Error connecting to the server!' }
} else {
// Server returns a response in response.error
newResponse = response.error;
}
return of(newResponse);
};
}
export class MyService {
...
saveTransaction(trans: Transaction): Observable<APIResponseBody> {
return this.http.post<APIResponseBody>(this.transUrl, trans)
.pipe(catchError(handleHttpError()));
}
...
}
export class MyComponent {
...
onSubmit() {
this.myService.saveTransaction(this.data) {
.subscribe((res: APIResponseBody) => {
if (res.error) {
this.toastService.showError(`${res.error}: ${JSON.stringify(res.attributes)}`);
} else if (res.trans) {
this.trans = res.trans;
}
})
}
}
...
}
但是,当我将错误处理移至 HttpInterceptor 时,它不起作用。在以下实现中,所有非 2xx http 错误似乎都被拦截器过滤掉了:
export class HttpInterceptorService implements HttpInterceptor {
constructor() { }
intercept (request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return next.handle(request)
.pipe(
catchError((response: any) => {
let newResponse;
if (response.status === 0) {
// Error connecting to the server
newResponse = { error: 'Error connecting to the server!' }
} else {
// Server returns a response in response.error
newResponse = response.error;
}
return of(newResponse);
})
);
}
}
}
export class MyService {
...
saveTransaction(trans: Transaction): Observable<APIResponseBody> {
return this.http.post<APIResponseBody>(this.transUrl, trans);
}
...
}
我的拦截器实现中缺少什么?
我认为这主要是因为没有在您的处理程序函数中返回正确的类型,您返回的是未知类型的可观察对象,这不是拦截器所期望的。看看这个并尝试一下:
@Injectable()
export class ErrorHandlerInterceptor implements HttpInterceptor {
intercept(request: HttpRequest < any > , next: HttpHandler): Observable < HttpEvent < any >> {
return next.handle(request).pipe(catchError((error) => this.errorHandler(error)));
}
// Customize the default error handler here if needed
private errorHandler(response: HttpErrorResponse): Observable < never > {
if (!environment.production) {
// Do something with the error
this.logger.logError('Request error ' + JSON.stringify(response));
}
// console.error(error);
const httpErrorCode = response.status;
switch (httpErrorCode) {
case 404:
this.router.navigateByUrl('/not-found');
break;
case 403:
this.router.navigateByUrl('/forbidden');
break;
case 500:
default:
// 500 Error Handing
break;
}
throw response;
}
}
拦截器需要 return 一个 Observable<HttpEvent>
,在你的例子中是 Observable<HttpResponse>
因此,无需直接 returning newResponse
对象,您只需创建一个 new HttpResponse
并将您的响应设置为响应的主体。
export class HttpInterceptorService implements HttpInterceptor {
constructor() { }
intercept (request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return next.handle(request)
.pipe(
catchError((response: any) => {
...
return of(new HttpResponse({ body: newResponse }));
})
);
}
}
干杯
你在这里提到了 2 个例子,所以我会尝试解释每个例子中发生了什么。
没有拦截器的第一个例子
我发现您使用 catchError
函数的方式存在问题。
saveTransaction(trans: Transaction): Observable<APIResponseBody> {
return this.http.post<APIResponseBody>(this.transUrl, trans)
.pipe(catchError(handleHttpError())); <-------------------------
}
在 catch 错误中,您要么传递一个箭头函数 () => { }
说明它的行为方式,要么传递对您案例中现有函数的引用 handleHttpError
.
所以正确的方法是
saveTransaction(trans: Transaction): Observable<APIResponseBody> {
return this.http.post<APIResponseBody>(this.transUrl, trans)
.pipe(catchError(handleHttpError)); <-------------------------
}
handleHttpError()
的方式是直接执行 handleHttpError 方法,然后将调用的响应传递给 catchError。另外,您声明的函数 handleHttpError
没有采用任何错误的参数。
所以第一个没有拦截器的例子是错误的,只是巧合,你看到的与你期望的相符。
拦截器的第二个例子
我们来看第二个拦截器的例子。您在 catchError 中传递的箭头函数没有正确实现,因此它不起作用。
尝试以下
catchError((response: HttpErrorResponse) => {
let newResponse;
if (response.error instanceof ErrorEvent) {
newResponse = { error: 'Error connecting to the server!' }
} else {
//The response object here holds 2 information
// response.error -> information about error
// response.status -> information about the status code returned
newResponse = response;
}
return of(newResponse);
});
我希望响应正文中的错误响应从我的 API 服务器一直流到我的组件以获得某些错误代码,例如 400 或 422。它在没有 HttpInterceptor 的情况下运行良好下面的实现。
function handleHttpError() {
return (response: any) => {
let newResponse;
if (response.status === 0) {
// Error connecting to the server
newResponse = { error: 'Error connecting to the server!' }
} else {
// Server returns a response in response.error
newResponse = response.error;
}
return of(newResponse);
};
}
export class MyService {
...
saveTransaction(trans: Transaction): Observable<APIResponseBody> {
return this.http.post<APIResponseBody>(this.transUrl, trans)
.pipe(catchError(handleHttpError()));
}
...
}
export class MyComponent {
...
onSubmit() {
this.myService.saveTransaction(this.data) {
.subscribe((res: APIResponseBody) => {
if (res.error) {
this.toastService.showError(`${res.error}: ${JSON.stringify(res.attributes)}`);
} else if (res.trans) {
this.trans = res.trans;
}
})
}
}
...
}
但是,当我将错误处理移至 HttpInterceptor 时,它不起作用。在以下实现中,所有非 2xx http 错误似乎都被拦截器过滤掉了:
export class HttpInterceptorService implements HttpInterceptor {
constructor() { }
intercept (request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return next.handle(request)
.pipe(
catchError((response: any) => {
let newResponse;
if (response.status === 0) {
// Error connecting to the server
newResponse = { error: 'Error connecting to the server!' }
} else {
// Server returns a response in response.error
newResponse = response.error;
}
return of(newResponse);
})
);
}
}
}
export class MyService {
...
saveTransaction(trans: Transaction): Observable<APIResponseBody> {
return this.http.post<APIResponseBody>(this.transUrl, trans);
}
...
}
我的拦截器实现中缺少什么?
我认为这主要是因为没有在您的处理程序函数中返回正确的类型,您返回的是未知类型的可观察对象,这不是拦截器所期望的。看看这个并尝试一下:
@Injectable()
export class ErrorHandlerInterceptor implements HttpInterceptor {
intercept(request: HttpRequest < any > , next: HttpHandler): Observable < HttpEvent < any >> {
return next.handle(request).pipe(catchError((error) => this.errorHandler(error)));
}
// Customize the default error handler here if needed
private errorHandler(response: HttpErrorResponse): Observable < never > {
if (!environment.production) {
// Do something with the error
this.logger.logError('Request error ' + JSON.stringify(response));
}
// console.error(error);
const httpErrorCode = response.status;
switch (httpErrorCode) {
case 404:
this.router.navigateByUrl('/not-found');
break;
case 403:
this.router.navigateByUrl('/forbidden');
break;
case 500:
default:
// 500 Error Handing
break;
}
throw response;
}
}
拦截器需要 return 一个 Observable<HttpEvent>
,在你的例子中是 Observable<HttpResponse>
因此,无需直接 returning newResponse
对象,您只需创建一个 new HttpResponse
并将您的响应设置为响应的主体。
export class HttpInterceptorService implements HttpInterceptor {
constructor() { }
intercept (request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return next.handle(request)
.pipe(
catchError((response: any) => {
...
return of(new HttpResponse({ body: newResponse }));
})
);
}
}
干杯
你在这里提到了 2 个例子,所以我会尝试解释每个例子中发生了什么。
没有拦截器的第一个例子
我发现您使用 catchError
函数的方式存在问题。
saveTransaction(trans: Transaction): Observable<APIResponseBody> {
return this.http.post<APIResponseBody>(this.transUrl, trans)
.pipe(catchError(handleHttpError())); <-------------------------
}
在 catch 错误中,您要么传递一个箭头函数 () => { }
说明它的行为方式,要么传递对您案例中现有函数的引用 handleHttpError
.
所以正确的方法是
saveTransaction(trans: Transaction): Observable<APIResponseBody> {
return this.http.post<APIResponseBody>(this.transUrl, trans)
.pipe(catchError(handleHttpError)); <-------------------------
}
handleHttpError()
的方式是直接执行 handleHttpError 方法,然后将调用的响应传递给 catchError。另外,您声明的函数 handleHttpError
没有采用任何错误的参数。
所以第一个没有拦截器的例子是错误的,只是巧合,你看到的与你期望的相符。
拦截器的第二个例子
我们来看第二个拦截器的例子。您在 catchError 中传递的箭头函数没有正确实现,因此它不起作用。
尝试以下
catchError((response: HttpErrorResponse) => {
let newResponse;
if (response.error instanceof ErrorEvent) {
newResponse = { error: 'Error connecting to the server!' }
} else {
//The response object here holds 2 information
// response.error -> information about error
// response.status -> information about the status code returned
newResponse = response;
}
return of(newResponse);
});