【问题标题】:Choose right RxJs operator in Angular 7 http interceptor在 Angular 7 http 拦截器中选择正确的 RxJs 运算符
【发布时间】:2020-06-22 13:51:35
【问题描述】:

我是 RxJs 的新手,如果您能建议我可以在拦截器中使用哪个运算符,我将不胜感激。 如果会话即将结束,我需要执行异步请求以刷新身份验证令牌:

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return next.handle(req)
        .pipe(
            //catchError operator works good, everything's ok here
            catchError((error: HttpErrorResponse) => {
                if (error instanceof HttpErrorResponse) {
                    let refreshToken = localStorage.getItem("refreshToken");

                    if (error && error.status === 401 && refreshToken) {
                        // 401 errors are most likely going to be because we have an expired token that we need to refresh.
                        if (this.refreshTokenInProgress) {
                            // If refreshTokenInProgress is true, we will wait until refreshTokenSubject has a non-null value
                            // which means the new token is ready and we can retry the request again
                            return this.refreshTokenSubject.pipe(
                                filter(result => result !== null),
                                take(1),
                                switchMap(() => next.handle(this.authRequest(req)))
                            );
                        }
                        else {
                            this.refreshTokenInProgress = true;
                            // Set the refreshTokenSubject to null so that subsequent API calls will wait until the new token has been retrieved
                            this.refreshTokenSubject.next(null);

                            return this.backend.auth.refreshToken().pipe(
                                switchMap((res) => {
                                    if (res) {
                                        //...
                                        return next.handle(this.authRequest(req));
                                    }
                                    else {
                                        this.backend.auth.logOut();
                                        window.location.reload();
                                    }

                                }),
                                // When the call to refreshToken completes we reset the refreshTokenInProgress to false
                                // for the next time the token needs to be refreshed
                                finalize(() => this.refreshTokenInProgress = false)
                            );
                        }
                    }
                    else {
                        this.refreshTokenInProgress = false;
                       //...                            
                        return throwError(error.error);
                    }

                }
            }),
            //The problem is here, I'm not sure which operator to use to handle successfull response
            tap(event => {
                if (event instanceof HttpResponse) {
                    if ((this.backend.auth.getAccessCookieExpireDate())) {
                        let diffMin = 0;
                        let diffMs = (Date.parse(this.backend.auth.getAccessCookieExpireDate()) - Date.parse(new Date().toUTCString()));
                        diffMin = Math.round(((diffMs % 86400000) % 3600000) / 60000);
                        if (diffMin <= 10) {
                            //refresh token automatically before it dies
                            let refreshToken = localStorage.getItem("refreshToken");
                            if (refreshToken) {
                                //this async request is not called, can't see it in network
                                this.backend.auth.refreshToken().pipe(
                                    tap((res) => {
                                        if (res) {
                                            //...
                                        }
                                        else {
                                            this.backend.auth.logOut();
                                            window.location.reload();
                                        }
                                    })
                                );

                            }
                        }
                    }  
                }
            })
        );
}

所以问题在于第二个运算符函数tap(),它适合我,因为我不需要返回 observable,但它不允许我执行异步请求。

【问题讨论】:

    标签: javascript rxjs angular6 angular7


    【解决方案1】:

    您可以将switchMap 用于 Observable,并将map 用于最后的传入事件。

    switchMap(event => {
      if (event instanceof HttpResponse) {
        //...
        return this.backend.auth.refreshToken().pipe(
          map(res => {
            //...
            return event;
          })
        );
      }
      return of(event);
    }) 
    

    【讨论】:

    • 如何让所有路径返回事件?否则我会收到错误type void is not assignable to type ObservableInput...
    • @GyuzalR 使用of 将输入作为 Observable 返回。
    猜你喜欢
    • 1970-01-01
    • 2019-08-03
    • 1970-01-01
    • 1970-01-01
    • 2023-03-13
    • 2020-03-20
    • 2014-02-13
    • 1970-01-01
    • 2017-11-07
    相关资源
    最近更新 更多