我希望在自定义http请求过期之前刷新令牌。当我确定令牌已过期但我给出以下控制台结果时,我会尝试使用我的代码:
Token refresh is required app.js:1:92855
updateToken() method inside app.js:1:93301
tokenNotExpired?: false app.js:1:92674
Token refresh is required app.js:1:92855
updateToken() method inside app.js:1:93301
tokenNotExpired?: false app.js:1:92674
Token refresh is required app.js:1:92855
updateToken() method inside app.js:1:93301
tokenNotExpired?: false app.js:1:92674
Token refresh is required app.js:1:92855
updateToken() method inside app.js:1:93301
tokenNotExpired?: false app.js:1:92674
............ lots of the same sentences and finally exception:
EXCEPTION: Uncaught (in promise): Error: Error in :0:0 caused by: too much recursion
k@http://localhost/xxx/node_modules/zone.js/dist/zone.min.js:1:11750
............
据我所知,在刷新令牌时它会进入一个无限循环。我已经使用按钮在其他地方测试了updateToken()方法,并且工作正常。
我做错了什么?
自定义http服务
import { Injectable } from '@angular/core';
import { Http, XHRBackend, RequestOptions, Request, RequestOptionsArgs, Response, Headers } from '@angular/http';
import { tokenNotExpired } from "angular2-jwt";
import { Observable } from "rxjs/Observable";
@Injectable()
export class HttpService extends Http {
constructor (backend: XHRBackend, options: RequestOptions) {
let token = localStorage.getItem('access_token'); // your custom token getter function here
options.headers.set('Authorization', `Bearer ${token}`);
super(backend, options);
}
request(url: string|Request, options?: RequestOptionsArgs): Observable<Response> {
let token = localStorage.getItem('access_token');
if (typeof url === 'string') { // meaning we have to add the token to the options, not in url
if (!options) {
// let's make option object
options = {headers: new Headers()};
}
options.headers.set('Authorization', `Bearer ${token}`);
} else { // we have to add the token to the url object
url.headers.set('Authorization', `Bearer ${token}`);
}
console.log("tokenNotExpired?: " + tokenNotExpired('access_token'));
if(tokenNotExpired('access_token')){ // if token is NOT expired
return super.request(url, options).catch(this.catchAuthError(this));
}else{ // if token is expired
console.log("Token refresh is required");
return this.updateToken()
.flatMap((result: boolean) => {
console.log("updateToken result");
console.log(result);
if (result) {
return super.request(url, options).catch(this.catchAuthError(this));
} else {
return Observable.throw(new Error('Can\'t refresh the token'));
}
});
}
}
updateToken(): Observable<any> {
console.log("updateToken() method inside");
let body: string = 'refresh_token=' + localStorage.getItem('refresh_token') + '&client_id=' + localStorage.getItem('resource') + '&grant_type=refresh_token';
return super.post(
localStorage.getItem("authUrl"),
body,
new RequestOptions({headers: new Headers({ 'Content-Type': 'application/x-www-form-urlencoded' })})
)
.map((response: Response) => {
let returnedBody: any = response.json();
console.log("post returnedBody");
console.log(returnedBody);
if (typeof returnedBody.access_token !== 'undefined'){
localStorage.setItem('access_token', returnedBody.access_token);
localStorage.setItem('refresh_token', returnedBody.refresh_token);
console.log("Token Refreshed: refreshed access_token");
console.log(localStorage.getItem('access_token'));
return true;
}
else {
return false;
}
});
}
private catchAuthError (self: HttpService) {
return (res: Response) => {
console.log(res);
return Observable.throw(res);
};
}
}
app模块
@NgModule({
imports: [ .......... ],
declarations: [ ....... ],
providers: [
{
provide: HttpService,
useFactory: (backend: XHRBackend, options: RequestOptions) => {
return new HttpService(backend, options);
},
deps: [XHRBackend, RequestOptions]
}
],
bootstrap: [ Application ]
})
答案 0 :(得分:2)
在updateToken
方法中,您调用的super.post
相当于Http.prototype.post.apply(this...)
,而super.post
会在内部调用this.request()
。
this
上下文是您的自定义HttpService
,最终是对HttpService
request
方法的反复调用。您应该致电super.request
:
return super.request(
new Request({
method: RequestMethod.Post,
url: localStorage.getItem("authUrl"),
body,
headers: new Headers({
'Content-Type': 'application/x-www-form-urlencoded'
})
})
)
.map((response: Response) => {
let returnedBody: any = response.json();
console.log("post returnedBody");
console.log(returnedBody);
if (typeof returnedBody.access_token !== 'undefined') {
localStorage.setItem('access_token', returnedBody.access_token);
localStorage.setItem('refresh_token', returnedBody.refresh_token);
console.log("Token Refreshed: refreshed access_token");
console.log(localStorage.getItem('access_token'));
return true;
} else {
return false;
}
});
另请注意,创建自定义Http服务可能不是最佳选择。
但也许您可以创建一个获取http注入的服务,因为您可能不需要进行身份验证只是为了从ajax调用中获取一些简单的静态数据。
这也可以避免在超出递归调用堆栈时遇到的问题。
@Injectable()
export class MyAuhtHttpService{
constructor(private http:Http){}
}