简体   繁体   English

Angular6 HttpClient catchError 不起作用

[英]Angular6 HttpClient catchError not working

CatchError is completelly ignored in 401 response. CatchError 在 401 响应中完全被忽略。

I have httpInterceptor that handles oauth2 authentication.我有处理 oauth2 身份验证的 httpInterceptor。

Relevant code is :相关代码是:

import { filter, take, switchMap, map, catchError } from 'rxjs/operators';
//ommited
if (authService.hasRefreshToken()) {
    return authService.doRefreshToken().pipe(switchMap(tokenResponse => {
            const accessToken = tokenResponse['access_token'];
            this.tokenSubject.next(accessToken);
            return <Observable<HttpEvent<any>>> next.handle(this.addToken(req, accessToken));
        }), catchError((err: any, caught: any) => {
            console.log(err)
            return Observable.throw(err);
        })
    )
}

AuthService class: AuthService 类:

export class AuthService {
    doRefreshToken() {
        //ommited
        return this.httpClient.post(environment.baseUrl + this.tokenEndpoint, null, requestOptions).pipe(
            map(tokenResponse => {
                this.saveToken(tokenResponse);
                return tokenResponse;
            }),
            catchError((err: any, caught: Observable<Object>) => {
                //refreshing token failed (refrech token invalid or expired) redirect to login and wipe everything
                this.logout();
                return Observable.throw(err);
            }));
    }
}

Everything works fine for 200 response, but 401 error is completely ignored.对于 200 响应,一切正常,但 401 错误被完全忽略。 Am i using this new catchError the wrong way ?我是否以错误的方式使用了这个新的 catchError ?

PS this piece of code was working just fine with plain old catch , but now when i migrated to angular6 pipe and catchError same stuff just doesnt work. PS 这段代码在普通的旧 catch 上工作得很好,但是现在当我迁移到 angular6 管道和 catchError 时,同样的东西就不起作用了。

EDIT :编辑 :

Breakpoint on catchError reveals catchError 上的断点显示

"SyntaxError: Unexpected end of input at AuthService.push../src/app/common/auth/auth.service.ts.AuthService.doRefreshToken “语法错误:在 AuthService.push../src/app/common/auth/auth.service.ts.AuthService.doRefreshToken 处意外结束输入

Actual response from the server is :来自服务器的实际响应是:

{
 "error" : "invalid_token",
 "error_description" : "Refresh token expired"
}

Headers :标题:

 Request Method: POST
 Status Code: 401 

I had the same issue of the catchError function being completely ignored.我有同样的问题,即catchError函数被完全忽略。 Since this simple and straightforward code used by @SeaBiscuit as described in the official Angular documentation did not work, I abandoned that approach to handling error responses and instead looked at HttpInterceptors.由于@SeaBiscuit 使用的这个简单直接的代码在官方Angular 文档中不起作用,我放弃了这种处理错误响应的方法,转而查看 HttpInterceptors。 And that worked!那奏效了!

I was inspired by the guidance of Luuk Gruijs in his article Global HTTP error catching in Angular 4.3+ to add the ErrorInterceptor shown below to my code.我受到 Luuk Gruijs 在他的文章Global HTTP error ErrorInterceptor in Angular 4.3+ 中的指导的启发,将下面显示的ErrorInterceptor添加到我的代码中。

Admittedly, the interceptor below may not be a perfect, but the most important part for handling errors in interceptors boils down to this:诚然,下面的拦截器可能并不完美,但在拦截器中处理错误最重要的部分归结为:

next.handle(request).pipe(tap(
  (event: HttpEvent<any>) => { },
  (error: any) => {
    // Handle errors here!
  }
))

Here's a more detailed glimpse at what I implemented:这是我实施的更详细的一瞥:

export class ErrorInterceptor implements HttpInterceptor {
  constructor() { }

  intercept (request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    if (request.method !== 'GET') {
      return next.handle(request);
    }

    const subject = new AsyncSubject<HttpEvent<any>>();

    next.handle(request)
    .pipe(
      tap((event: HttpEvent<any>) => {
        // Let HttpResponses pass through interceptor without interaction
        if (event instanceof HttpResponse) {
          subject.next(event);
          subject.complete();
        }
      }, (error: any) => {
        if (error instanceof HttpErrorResponse) {
          const errorEvent = new HttpResponse({
            body: {
              message: error.error.message,
              status: error.status,
              statusText: error.statusText
            }
          });

          subject.next(errorEvent);
          subject.complete();
        }
      })
    ).subscribe();

    return subject;
  }
}

I also modified my service to accept that manually created response body:我还修改了我的服务以接受手动创建的响应正文:

return this.http.get<MyObjI | ErrorI>(url, {params});

... where ErrorI is: ...其中ErrorI是:

export interface ErrorI {
  message: string;
  status: number;
  statusText: string;
}

Hopefully handling errors in an interceptor does the trick for you, too!希望在拦截器中处理错误也能帮到你!

Observable.throw() cannot be use in a return statement . Observable.throw()不能在 return 语句中使用

> Creates an Observable that emits no items to the Observer and immediately emits an error notification. > 创建一个不向观察者发出任何项目并立即发出错误通知的 Observable。

that is why you are getting the syntax error on AuthService.doRefreshToken这就是您在AuthService.doRefreshToken上收到语法错误的AuthService.doRefreshToken

Observable.throw() throws an error that is why you are not allowed to use it in a return statement. Observable.throw()会抛出一个错误,这就是为什么你不能在return语句中使用它的原因。

It is the same thing as the following,它与以下内容相同,

return throw Error("")

You can easily get complaining from your ESlint.你很容易从 ESlint 那里得到抱怨。

Anyway, since this is a old question, you'd should be using the new API but I hope this can help users from the old rxjs API.无论如何,由于这是一个老问题,您应该使用新 API,但我希望这可以帮助来自旧 rxjs API 的用户。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM