2017-05-15 37 views
1

如果自定义http请求过期,我想刷新令牌。我尽我的代码时,我敢肯定,该令牌已过期,但它提供了以下控制台结果:自定义http请求之前的角度2刷新令牌

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 
[email protected]://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); 
     }; 
    } 
} 

应用模块

@NgModule({ 
    imports: [ .......... ], 
    declarations: [ ....... ], 
    providers: [ 
    { 
     provide: HttpService, 
     useFactory: (backend: XHRBackend, options: RequestOptions) => { 
     return new HttpService(backend, options); 
     }, 
     deps: [XHRBackend, RequestOptions] 
    } 

    ], 
    bootstrap: [ Application ] 
}) 
+0

updateToken()内的'super.post'将在内部调用'this.request' ...'this'是您自定义的'HttpService'。 – n00dl3

+0

@ n00dl3那么我可以在不涉及“HttpService”的情况下调用帖子吗? –

+0

不行,你应该调用'super.request'来代替。 (如果它当然没有调用任何重写方法)。 – n00dl3

回答

2

里面你updateToken方法,你在呼唤super.post这将相当于Http.prototype.post.apply(this...),并super.post将调用内部this.request()

this上下文是您的自定义HttpService,它最终在HttpServicerequest方法recusrsive调用。你应该叫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){} 

}