在角度5中刷新访问令牌时发出问题

时间:2018-02-20 08:59:20

标签: angular rxjs rxjs5 angular-http-interceptors angular-httpclient

如果用户收到未经授权的错误,我想刷新令牌。我试图在拦截器中处理这个问题。以下是代码:

intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
      return next.handle(req).do((event: HttpEvent<any>) => {
      if (event instanceof HttpResponse) {
      }
    }, (err: any) => {
      if (err instanceof HttpErrorResponse) {
        if (err.status === 401) {
          fn.refreshToken(req, next);

        }
      }
    });
  }

我有函数refreshToken,我试图调用API来刷新令牌:

refreshToken(req, next) {
    const headers = new HttpHeaders()
        .set('Content-Type', 'application/x-www-form-urlencoded');

    const body = new HttpParams()
      .set('refresh_token', localStorage.getItem('refreshToken'));
     this._http.post('/refreshtoken',  body.toString(), {headers}).subscribe(
       (data) => {
         const header = `Bearer ${(<any>data).accessToken}`;
        const newRequest = req.clone({ headers: req.headers.set('Authorization',  header)});
        return next.handle(newRequest);

       }),
        (err) => {
          console.log(err);
        }

  }

但上面代码的问题是我无法调用克隆的请求。仅在我调用subscribe方法时才触发请求。如下图所示:

 return next.handle(newRequest).subscribe();

我想如果令牌过期,请调用服务刷新令牌并重新发送失败的原始请求。而且调用失败的原始请求的订阅方法。

如果我的方法是正确的,请告诉我。

如果是,那么我在这里失踪了。

1 个答案:

答案 0 :(得分:1)

拦截器必须返回一个Observable,并且可以调用next.handle(req)本身,所以我认为你可以调用next.handle(req)两次,但更好,更多“Rx”解决方案是使用catch运算符并合并原始源Observable。此外,您还需要更改refreshToken以返回Observable,并且您可能希望使用do()存储新令牌。

refreshToken(...): Observable<any> {
  return this._http.post('/refreshtoken', ...)
    .do(/* save token here */);
}

intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
  return next.handle(req)
    .catch((err, source) => {
      if (err instanceof HttpErrorResponse && err.status === 401) {
        return this.refreshToken(...)
          .concatMap(() => next.handle(req /* ... or updated req */ ));
          // or you could use .concatMap(() => source) to trigger the same request again
      }
      throw err;
    })
}