Angular防止异步请求上的多个令牌刷新 [英] Angular prevent multiple token refresh on asynchronous requests

查看:67
本文介绍了Angular防止异步请求上的多个令牌刷新的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我所有的http请求都通过自定义的 HttpService .发送令牌之前,该服务会在令牌过期时刷新该令牌.

All my http requests go through the custom HttpService. This service refreshes the token when it's expired before sending the request.

它可以正常工作,但是如果加载的页面有多个http请求,它将刷新令牌多次.例如,如果页面通过服务有10个请求,则意味着令牌刷新是10倍.

It works fine but it refreshes the token multiple times if the loaded page has multiple http requests. For example, if the page has 10 requests through the services, this means 10 times token refresh.

我试图通过示例代码对此进行描述:

I've tried to describe this by sample code:

加载的页面和使用的服务

export class Page1 implements OnInit {
    constructor(
        private service1: Service1,
        private service2: Service2
    ) { }

    ngOnInit() {
        this.service1.getData...
        this.service2.getData...        
    }   
}

@Injectable()
export class Service1 {
    constructor(
        private httpService: HttpService
    ) {}

    getData(): Observable<any> {
        return this.httpService.get(.....)
            .map((response: Response) => {
                return response.json();
            });
    }
}
@Injectable()
export class Service2 {
    constructor(
        private httpService: HttpService,
        private service1: Service1
    ) {}

    getData(): Observable<any> {
        return this.httpService.get(.....)
            .map((res: Response) => res.json().response)
            .flatMap((newItem: Item) => {
                    this.service1.getData(...)
            });
    }
}

自定义http服务

@Injectable()
export class HttpService extends Http {

    constructor (backend: XHRBackend, options: RequestOptions) {
        .............
    }

    request(url: string|Request, options?: RequestOptionsArgs): Observable<Response> {

        ................

        if(tokenNotExpired('access_token')){ // if token is NOT expired

            return super.request(url, options);

        }else{  // if token is expired

            return this.updateToken()
                .flatMap((result: boolean) => {
                    return this.request(url, options);  
            });
        }
    }

    updateToken(): Observable<boolean> {

        // set the new token
        .....

    }
}

如何通过在que中设置这些请求并仅在新令牌准备好后才发送它们,来对每个请求刷新令牌?

How can I perevent the token refresh per request by setting these requests in que and send them only when the new token is ready?

注意:我不知道这是否有关系,但是服务请求可以通过 flatMap forkJoin ....

Note: I don't know if it's matter but the service requests can be combined by flatMap or forkJoin....

更新1

我已经根据 @bviale 的答案更新了代码.

I've updated my code according to @bviale's answer.

request(url: string|Request, options?: RequestOptionsArgs): Observable<Response> {

    ................

    if(tokenNotExpired('access_token')){ // if token is NOT expired

        return super.request(url, options);

    } else {  // if token is expired

        // There is already a call to updateToken() in progress,
        // wait for it to finish then process the request
        if (this.updateTokenPromise) {
            return Observable.fromPromise(return this.updateTokenPromise.then(() => {
                return this.request(url, options);  
            }));
        }
        // Start to call updateToken(), then resolve the promise
        else {
            this.updateTokenPromise = new Promise((resolve, reject) => {
                this.updateToken().toPromise()
                    .then((result: boolean) => {
                        resolve(result);
                    });
            });

            return Observable.fromPromise(return this.updateTokenPromise.then(() => {
                return this.request(url, options);
            }));
        }
    }
}

我更新的 request()方法可以完美地停止请求,仅调用一次 updateToken(),获取令牌,然后针对每个请求调用请求我现在收到以下错误:

My updated request() method perfectly stops the requests, invokes the updateToken() only one time, gets the token, and then calls the requests but for each request I get the following error now:

我注意到服务调用返回以下响应,这当然会导致 e.json不是函数异常:

I've noticed that the service calls returns the following response which ofcourse will cause e.json is not a function exception:

Object { _isScalar: false, source: Object, operator: Object }

我认为这也是我需要投射的东西吗?

I think this is also something I need to cast?

推荐答案

您可以像下面这样调用 updateToken()来创建自己的Promise:

You can create your own Promise when you call updateToken() like this :

@Injectable()
export class HttpService extends Http {

    private updateTokenPromise: Promise<any>;

    constructor (backend: XHRBackend, options: RequestOptions) {
        .............
    }

    request(url: string|Request, options?: RequestOptionsArgs): Observable<Response> {

        ................

        if(tokenNotExpired('access_token')){ // if token is NOT expired

            return super.request(url, options);

        } else {  // if token is expired

            // There is already a call to updateToken() in progress,
            // wait for it to finish then process the request
            if (this.updateTokenPromise) {
                return this.updateTokenPromise.then(() => {
                    return this.request(url, options);  
                });
            }
            // Start to call updateToken(), then resolve the promise
            else {
                this.updateTokenPromise = new Promise((resolve, reject) => {
                    this.updateToken()
                        .then((result: boolean) => {
                            resolve(result);
                        });
                });

                return this.updateTokenPromise.then(() => {
                    return this.request(url, options);
                });
            }
        }
    }

    updateToken(): Observable<boolean> {

        // set the new token
        .....

    }
}

这样,您就不会有多个并行调用 updateToken()

This way you won't have multiple parallel calls of updateToken()

这篇关于Angular防止异步请求上的多个令牌刷新的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆