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

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何在调用WS之前等待某事相关的知识,希望对你有一定的参考价值。

我的应用使用带有令牌的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,我不知道如何等待和解决?

答案

你应该使用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();
}

如果你的电话是无法观察的。只是包裹它。

另一答案

所以你要做的是,如果更新token,立即调用wsCall,如果没有更新token,请调用handleAccessTokenExpiration,然后调用wsCall。你可以利用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());
    }
}

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

return this.isTokenBeingRenewed ? wsCall() : this.handleAccessTokenExpiration().switchMap(() => wsCall());

以上是关于如何在调用WS之前等待某事的主要内容,如果未能解决你的问题,请参考以下文章

QT 重绘/重绘/更新/做某事

从活动中调用片段事件

等待侦听器完成

如何在调用我的 api 之前减慢/​​等待?

HTML5 Websocket 在发送消息之前等待连接和就绪状态更改

如何使用 Timer 类调用方法,做某事,重置计时器,重复?