Angular6 HttpClient catchError无法正常工作

时间:2018-06-10 10:01:45

标签: angular rxjs

在401响应中完全忽略了CatchError。

我有httpInterceptor来处理oauth2身份验证。

相关代码是:

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类:

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);
            }));
    }
}

对于200响应,一切正常,但401错误完全被忽略。 我是否以错误的方式使用这个新的catch错误?

P.S。这段代码用普通的旧捕获工作得很好,但现在当我迁移到angular6管道和catchError时,同样的东西就不起作用了。

编辑:

catchError上的断点显示

  

&#34; SyntaxError:意外的输入结束       在AuthService.push ../ src / app / common / auth / auth.service.ts.AuthService.doRefreshToken

服务器的实际响应是:

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

标题:

 Request Method: POST
 Status Code: 401 

2 个答案:

答案 0 :(得分:0)

我遇到了catchError函数被完全忽略的同一问题。由于在官方Angular documentation中描述的@SeaBiscuit使用的这种简单直接的代码不起作用,因此我放弃了该方法来处理错误响应,而转而使用HttpInterceptors。那行得通!

Luuk Gruijs在他的文章Global HTTP error catching in Angular 4.3+中的指导启发了我,将下面显示的ErrorInterceptor添加到了我的代码中。

诚然,下面的拦截器可能并不完美,但是处理拦截器中错误的最重要部分归结为:

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

以下是我实施的详细信息:

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;
  }
}

我还修改了服务,以接受手动创建的响应正文:

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

...,其中ErrorI是:

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

希望在拦截器中处理错误也能帮到您!

答案 1 :(得分:0)

Observable.throw() 不能在return语句中使用

> Creates an Observable that emits no items to the Observer and immediately emits an error notification.

这就是为什么在AuthService.doRefreshToken上出现语法错误的原因

Observable.throw()引发错误,这就是为什么不允许您在return语句中使用它的原因。

与以下内容相同

return throw Error("")

您可以轻松地从ESlint抱怨。

无论如何,由于这是一个古老的问题,您应该使用新的API,但我希望这可以为旧的rxjs API的用户提供帮助。