简体   繁体   English

Angular防止异步请求刷新多个令牌

[英]Angular prevent multiple token refresh on asynchronous requests

All my http requests go through the custom HttpService . 我所有的http请求都通过自定义HttpService This service refreshes the token when it's expired before sending the request. 发送令牌之前,此服务在令牌过期时会刷新。

It works fine but it refreshes the token multiple times if the loaded page has multiple http requests. 它工作正常,但是如果加载的页面有多个http请求,它将刷新令牌多次。 For example, if the page has 10 requests through the services, this means 10 times token refresh. 例如,如果页面通过服务有10个请求,则意味着令牌刷新是10次。

I've tried to describe this by sample code: 我试图通过示例代码来描述:

loaded page and used services 加载的页面和使用的服务

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(...)
            });
    }
}

custom http service 自定义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
        .....

    }
}

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? 如何通过在que中设置这些请求并仅在新令牌准备好后才发送它们,来为每个请求刷新令牌?

Note: I don't know if it's matter but the service requests can be combined by flatMap or forkJoin .... 注意:我不知道这是否重要,但是服务请求可以通过flatMapforkJoin ...组合。

Update 1 更新1

I've updated my code according to @bviale 's answer. 我已经根据@bviale的答案更新了代码。

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);
            }));
        }
    }
}

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: 我更新的request()方法可以完美地停止请求,仅调用一次updateToken() ,获取令牌,然后调用请求,但是对于每个请求,我现在得到以下错误:

在此处输入图片说明

I've noticed that the service calls returns the following response which ofcourse will cause e.json is not a function exception: 我注意到服务调用返回以下响应 ,这当然会导致e.json is not a function异常:

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

I think this is also something I need to cast? 我认为这也是我需要投射的东西吗?

You can create your own Promise when you call updateToken() like this : 您可以像这样调用updateToken()来创建自己的Promise:

@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
        .....

    }
}

This way you won't have multiple parallel calls of updateToken() 这样,您将不会有多个并行调用的updateToken()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM