如何在调用WS之前等待某事

时间:2018-03-05 14:29:18

标签: angular rxjs

我的应用程序使用带有令牌的SSO身份验证,该令牌可能会过期。

点击" admin"按钮,我需要为页面的几个部分调用几个WS(这些调用没有链接)。

如果我的令牌过期,则第一次WS调用将导致401错误。然后我会要求更新令牌。 我试图做的是保持跟随ws呼叫,直到令牌更新完成。

我有类似的东西:

private isTokenBeingRenewed: BehaviorSubject<boolean> = new BehaviorSubject(false);
...
private handleAccessTokenExpiration(wsCall: Function, growlSuccessMsg: string, growlTitle?: string): Observable<Response> {
        // flag token being renewed
        this.isTokenBeingRenewed.next(true);
        //start token renewal
        return this.oidcSecurityService.refreshSession().flatMap(event => {
            // Call WS again when token is renewed
            return wsCall()
                .catch(error => {
                    return Observable.throw(...);
                })
                .do((res: Response) => {
                    ...
                }, (error: any) => {
                    return Observable.throw(...);
                })
                .finally(() => {
                    // flag token renewal is done
                    this.isTokenBeingRenewed.next(false);
                });
        });
    }

在我的ws呼叫功能上我有:

 private handleWSResponse(wsCall: Function,
        showGrowlSuccess: boolean,
        growlTitle?: string,
        growlSuccessMsg?: string): Observable<Response> {

        // Avoid call renew multiple times.
        return this.isTokenBeingRenewed.flatMap(isRenewing => {
            // If token renewal is not in progress, calls WS
            if (!isRenewing) {
                // Call WS
            }
        }
}

问题是,当isRenewing === true时,Observable已解决,但不会返回任何内容。如果isRenewing = true,我不知道如何等待和解决?

2 个答案:

答案 0 :(得分:0)

所以,您要做的是,如果续订token,请立即致电wsCall,如果token未续订,请致电handleAccessTokenExpiration,然后致电{{ 1}}。您可以使用wsCall来执行&#34;等待&#34;:

switchMap()

或者您可以在一个班轮中完成:

private handleWSResponse(wsCall: Function,
                         showGrowlSuccess: boolean,
                         growlTitle?: string,
                         growlSuccessMsg?: string): Observable<Response> {

    if (this.isTokenBeingRenewed) {
        return wsCall();
    } else {
       //handle token first
       //arguments here is omitted for brevity
        return this.handleAccessTokenExpiration()
            .switchMap(() => wsCall());
    }
}

答案 1 :(得分:0)

你应该使用HttpInterceptor来实现它!

@Injectable()
export class AuthInterceptor implements HttpInterceptor {
   private authService: AuthService;

   constructor(private inj: Injector) {}

   intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
       if (request.url.includes('/not-authorized')) {
          return next.handle(request);
       }
       this.authService = this.inj.get(AuthService);

       return this.authService.getRawAccessToken()
           .switchMap(token => {
              request = request.clone({
                  setHeaders: {
                      Authorization: `Bearer ${token}`
                  }
               });
               return next.handle(request);
           });
    }
}

该示例与您的方案不完全匹配,但方法应该这样做。 这样的事情。在这里,您必须划分必须获得授权的API。然后,您可以在auth服务中检查令牌过期。只有令牌再次有效时,“authservice”提供的Observable才应解决。然后你有一个点可以控制每个呼叫。 在我看来,这是最简单的方法。 此外,在这种场景中,应该使用switchMap。

如果您在这里不使用Angular,也可以使用相同的概念。只需订阅行为主题并过滤所有错误值。但是,如果您始终对第一个服务进行异步调用以检查令牌是否已过期,则您将始终丢失一些调用。您应该可以使用oidc synchronous来检查到期时间:

private isTokenBeingRenewed: BehaviorSubject<boolean> = new BehaviorSubject(false);

public handleAccessTokenExpiration(): Observable<boolean> {
    this.isTokenBeingRenewed.next(true);
    //start token renewal
    this.oidcSecurityService.refreshSession()
         .subscribe(event => this.isTokenBeingRenewed.nect(false);
    return this.isTokenBeingRenewed;
}

在来电者中:

public doSth() {
    handleAccessTokenExpiration
        .filter(result => !result)
        .switchMap(result => doWsCall())
        .sunscribe();
}

如果你的电话没有被观察到。只是包裹它。