I have a two functions as below:
refreshAccessToken() {
let rt = this.injector.get(LocalStorageService);
var tokenData = rt.getAuthorizationData();
var refreshToken = tokenData.refresh_token;
var refreshToken = localStorage.getItem('userRefreshToken');
if (refreshToken !== null) {
var data = "grant_type=refresh_token&refresh_token=" + refreshToken;
var basicAuth = btoa("crmClient1:crmSuperSecret");
var headerData = {
"Content-Type": "application/x-www-form-urlencoded",
"Authorization": "Basic " + basicAuth,
"No-Auth": "True",
'Access-Control-Allow-Origin': '*'
};
var reqHeader = new HttpHeaders(headerData);
this.http.post(this.tokenUrl, data, {
headers: reqHeader
})
.subscribe((response: any) => {
this.localStorageService.setAuthorizationData(response);
console.log("I need to be called first");
});
} else {
return null;
}
}
getNewAccessToken(): Observable < string > {
this.refreshAccessToken();
console.log("I need to be called as a second value");
var varTokenData = this.localStorageService.getAuthorizationData();
var newAccessToken = varTokenData.access_token;
this.newat = newAccessToken;
return of(this.newat);
}
I am calling refreshAccessToken()
function inside getNewAccessToken()
function. Here, the code is doing fine except that the codes:
console.log("I need to be called as a second value");
var varTokenData = this.localStorageService.getAuthorizationData();
var newAccessToken = varTokenData.access_token;
this.newat = newAccessToken;
return of(this.newat);
are executed before the complete execution of function refreshAccessToken()
. How do I make other codes wait for execution until the refreshAccessToken()
function is completely executed in angular 6?
The error I am getting is as below:
The section of AuthInterceptor from where I a calling getNewAccessToken() function is as below:
//generating new token from refresh_token
handle401Error(req: HttpRequest<any>, next: HttpHandler) {
console.log("Error 401 called");
if (!this.isRefreshingToken) {
this.isRefreshingToken = true;
// Reset here so that the following requests wait until the token
// comes back from the refreshToken call.
this.tokenSubject.next(null);
return this.loginService.getNewAccessToken()
.pipe(
switchMap((newToken: string) => {
if (newToken) {
this.tokenSubject.next(newToken);
//this.isRefreshingToken=false;
return next.handle(this.addToken(req, newToken));
}
// If we don't get a new token, we are in trouble so logout.
//this.isRefreshingToken=false;
return this.logout();
}),
catchError(error => {
// If there is an exception calling 'refreshToken', bad news so logout.
//this.isRefreshingToken=false;
//console.log(error);
return this.logout();
})
//)
),
finalize(()=>{
this.isRefreshingToken=false;
});
} else {
return this.tokenSubject
.pipe(
filter(token => token !=null)
),
take(1),
switchMap((token: string )=> {
return next.handle(this.addToken(req,token));
});
}
}
You can return
an Observable
from your refreshAccessToken
method:
import { of } from 'rxjs';
import { tap } from 'rxjs/operators';
refreshAccessToken(): Observable<any> {
...
if (refreshToken !== null) {
...
return this.http.post(this.tokenUrl, data, {
headers: reqHeader
})
.pipe(tap(response => this.localStorageService.setAuthorizationData(response)));
} else {
return of(null);
}
}
And then subscribe to it from your getNewAccessToken
method like this:
getNewAccessToken(): Observable<string> {
this.refreshAccessToken()
.subscribe(response => {
...
});
}
Alternatively:
You could use async
/ await
which were introduced in ES2017. Since they work only with functions dealing with promise
s and not Observable
s, you will have to change your functions a bit to return a promise
instead of Observable
.
Here's how:
import { of } from 'rxjs';
import { tap } from 'rxjs/operators';
refreshAccessToken() {
...
if (refreshToken !== null) {
...
return this.http.post(this.tokenUrl, data, {
headers: reqHeader
})
.pipe(tap(response => this.localStorageService.setAuthorizationData(response)))
.toPromise();
} else {
return of(null).toPromise();
}
}
And then declare getNewAccessToken
as async
and await
refreshAccessToken
:
async getNewAccessToken() {
await this.refreshAccessToken();
...
}
import { forkJoin } from "rxjs";
async ngOnInit() {
let data = await this.getDataFromMultipleApis();
console.log(data);
}
getDataFromMultipleApis(){
return new Promise((resolve, reject) => {
forkJoin(
this.Service.api1(),
this.Service.api2()
).subscribe(docs => {
resolve(docs);
});
});
}
You could leverage TypeScript's async/await pattern if you convert the Observable
objects to Promise
s. Then you can write code that looks more synchronous. It's worth calling out, however, that the code itself is still using callbacks and Promises to actually execute, but that's abstracted away from you by the syntactic sugar.
async getNewAccessToken(): Promise<string> {
// Your refreshAccessToken() needs to always return an Observable now.
await this.refreshAccessToken().toPromise();
console.log("I need to be called as a second value");
var varTokenData = this.localStorageService.getAuthorizationData();
var newAccessToken = varTokenData.access_token;
this.newat = newAccessToken;
return this.newat;
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.