2017-08-15 53 views
1

我想刷新一個JWT令牌,當我得到一個特定的異常,當它是另一個異常,我的ErrorHandler應該處理它們。角2 http異常處理程序和jwt刷新

我有一段代碼,一個是令牌刷新工作的地方,另一個是代碼處理異常處理程序的代碼段,但我不能以工作方式組合它們。

問題是我不能拋出異常,並用我的ErrorHandler在observable中捕獲異常。

這裏是我可以刷新令牌的代碼。當它失敗時,它會檢查錯誤代碼是否爲token_expired,何時它會刷新令牌並重試請求。

export class HttpErrorService extends Http { 

    constructor(backend: XHRBackend, defaultOptions: RequestOptions) { 
    super(backend, defaultOptions); 
    } 

    request(url: string | Request, options?: RequestOptionsArgs, disableRefresh = false): Observable<Response> { 
     return super.request(url, options).catch((error: Response) => { 
     // Refresh token on token_expired exception. 
     if (!disableRefresh && error.status === 401 && error.json().error.code === 'token_expired') { 
      return this.renewToken().flatMap((response) => { 
      const res = response.json(); 
      // Replace the token in storage. 
      localStorage.setItem('__token', res.data.token); 

      // Replace request the token with the new one. 
      if (url instanceof Request) { 
       url.headers.set('Authorization', 'Bearer ' + res.data.token); 
      } else if (options) { 
       options.headers.set('Authorization', 'Bearer ' + res.data.token); 
      } 

      // To prevent a loop disable refreshing at the next request. 
      return this.request(url, options, true); 
      }); 
     } 

     // Here I want to throw the exception. 
     // I need to be able to catch it with my exception handler. 
     // throw error; doesn't work. 
     return Observable.throw(error); 
     }); 
    } 

    private getBaseUrl(): string { 
    return environment.base_uri; 
    }; 

    renewToken(): Observable<Response> { 
    const headers = new Headers(); 
    headers.append('Authorization', 'Bearer ' + localStorage.getItem('__token')) 

    return this.post(this.getBaseUrl() + '/auth/refresh', {}, {headers: headers}); 
    } 
} 

上述唯一的壞處是我無法在異常處理程序中捕捉異常。

以下代碼可能會拋出ErrorHandler可以捕獲的異常。但我不知道我怎麼能刷新令牌一個電話...

export class HttpErrorService extends Http { 

    constructor(backend: XHRBackend, defaultOptions: RequestOptions) { 
    super(backend, defaultOptions); 
    } 

    request(url: string | Request, options?: RequestOptionsArgs, disableRefresh = false): Observable<Response> { 
    return Observable.create(observer => { 
     super.request(url, options).subscribe(
     res => observer.next(res), 
     err => { 
      if (!disableRefresh && err.status === 401 && err.json().error.code === 'token_expired') { 
      // I can't return this.renewToken()... 
      } 
      observer.error(err); 
      throw new HttpException(err); // this is getting catched by the ErrorHandler 
     }, 
     () => observer.complete); 
    }); 
    } 

    private getBaseUrl(): string { 
    return environment.base_uri; 
    }; 

    renewToken(): Observable<Response> { 
    const headers = new Headers(); 
    headers.append('Authorization', 'Bearer ' + localStorage.getItem('__token')) 

    return this.post(this.getBaseUrl() + '/auth/refresh', {}, {headers: headers}); 
    } 
} 

我的錯誤處理程序是隻包含一個console.log()
https://angular.io/api/core/ErrorHandler

我該如何得到這個工作?

+0

也可以添加實際調用請求函數和ErrorHandler的代碼嗎? – trungk18

+0

@ trungk18我重寫了Http類,所以每個http請求都使用請求函數。它是默認的Http庫。 ErrorHandler只是一個'console.log();' –

+0

您好,您可以嘗試「拋出Observable.throw(錯誤)」而不是「返回Observable.throw(錯誤)」在您的第一塊代碼? – trungk18

回答

0

幾個小時後,我終於找到了解決方案!

export class HttpErrorService extends Http { 

    constructor(backend: XHRBackend, defaultOptions: RequestOptions) { 
    super(backend, defaultOptions); 
    } 

    request(url: string | Request, options?: RequestOptionsArgs, disableRefresh = false): Observable<Response> { 
    return Observable.create(observer => { 
     super.request(url, options).retryWhen(attempts => this.retryRequest(attempts)).catch((error: Response) => { 
     // Refresh token on token_expired exception. 
     if (!disableRefresh && error.status === 401 && error.json().error.code === 'token_expired') { 
      return this.renewToken().flatMap((response) => { 
      const res = response.json(); 
      // Replace the token in storage. 
      localStorage.setItem('__token', res.data.token); 

      // Replace request the token with the new one. 
      if (url instanceof Request) { 
       url.headers.set('Authorization', 'Bearer ' + res.data.token); 
      } else if (options) { 
       options.headers.set('Authorization', 'Bearer ' + res.data.token); 
      } 

      // To prevent a loop disable refreshing at the next request. 
      return this.request(url, options, true); 
      }); 
     } 

     throw Observable.throw(error); 
     }).subscribe(
     res => observer.next(res), 
     err => { 
      observer.error(err); 
      throw new HttpException(err); 
     } 
    ); 
    }); 
    } 

    private getBaseUrl(): string { 
    return environment.base_uri; 
    }; 

    renewToken(): Observable<Response> { 
    const headers = new Headers(); 
    headers.append('Authorization', 'Bearer ' + localStorage.getItem('__token')) 

    return this.post(this.getBaseUrl() + '/auth/refresh', {}, {headers: headers}); 
    } 

    retryRequest(attempts: any) { 
    let count = 0; 

    return attempts.flatMap(error => { 
     return ++count >= 3 ? Observable.throw(error) : Observable.timer(count * 1000); 
    }); 
    } 

}