2017-08-10 35 views
2

如何使用新標頭處理克隆請求?使用攔截器在Angular 4.3中重新嘗試使用新標頭的Http請求

我想在第一個請求失敗後生成的新令牌在新的攔截器中執行克隆請求!

  • 如果犯錯401 - >刷新令牌
  • 發回具有新標題

這裏是我的嘗試以前的請求的副本:

refreshSessionToken() { 
    return this.http.post('/connect', {}) 
     .map(res => { 
     const token = res.json(); 
     localStorage.setItem('token', token); 
     return token; 
     }); 
    } 


// Get the headers 
const headers = getAuthenticationHeaders(); 
const reqMain = req.clone({headers: headers}); 
return next.handle(reqMain).catch(err => { 

     this.refreshSessionToken() 
      .subscribe(token => { 
       const t = token.token_id; 
       const clonedReq = req.clone({headers: req.headers.set('access-token', t)}); 

       return next.handle(clonedReq); 
        }); 
     }) 

得到一個日誌clonedReq我可以看到該令牌已刷新,但訂閱內的請求(clonedReq)未執行,爲什麼?!

我嘗試了其他方法來刷新智威湯遜,但它似乎並沒有在我的情況下工作,對如何處理它的任何幫助?

謝謝!

我的結果是什麼?

  • 發送1#HTTP請求
  • 1#請求失敗
  • 刷新令牌(獲取/設置令牌)
  • 克隆先前請求並添加刷新令牌
  • 發送2#HTTP請求
  • 2#請求成功

Simil IAR問題:

http-interceptor-refresh-jwt-token

+1

如果返回next.handle(clonedReq);是可觀察的(我懷疑是什麼),那麼你將需要訂閱它.. – codeSetter

+0

@Dipak有道理!感謝:D:D 現在克隆的請求被觸發,並且2#請求結果成功。 - 訂閱中的日誌被激發兩次(HTTP請求只發送一次..所以它很好),但我不確定它爲什麼會發生? 'next.handle(clonedReq) .subscribe(()=> console.log('Cloned Request Fired Twice!'));' – 39ro

+0

內部回報是罪魁禍首,你這樣做的方式是混亂的......雖然它可以工作,但我不喜歡它。他們是更好的方式...我會回答一旦我回家...等等... – codeSetter

回答

4

繼通用方法可用於攔截以及添加/刪除附加信息調用和響應。

好的,這裏是完整的代碼。

InterceptedHttp.ts


import { Injectable } from "@angular/core"; 
import { RequestOptions, Http, Headers, Response, RequestMethod, URLSearchParams } from "@angular/http"; 
import { Observable, Observer } from 'rxjs/Rx'; 

import 'rxjs/add/operator/map'; 
import 'rxjs/add/operator/catch'; 
import "rxjs/add/operator/mergeMap"; 

@Injectable() 
export class InterceptedHttp { 

    constructor(private http: Http) { } 

    getRequestOption(method: RequestMethod | string, data?: any, params?: any): RequestOptions { 
     let options = new RequestOptions(); 
     options.headers = new Headers(); 
     //options.headers.append('Content-Type', 'application/json'); 
     options.method = method; 

     let token: string = localStorage.getItem('token'); 
     //if (token) options.headers.append('Authorization', 'Bearer ' + token); 

     if (data) options.body = data; 

     if (params) { 
      options.search = new URLSearchParams(); 
      let keys: string[] = Object.keys(params); 

      keys.forEach((key, index) => { 
       options.search.set(key, params[key]); 
      }); 
     } 

     return options; 
    } 

    refreshSessionToken(): Observable<string> { 
     //Put some user identification data 
     let userData: any = {id: 'abc'}; 
     return this.http.post('/refreshToken', userData) 
      .map(res => { 
       let token = res.json(); 
       localStorage.setItem('token', token); 
       return token; 
      }); 
    } 

    getApiResponse<T>(url: string, method: RequestMethod | string, data?: Object): Observable<T> { 
     let op1: RequestOptions = this.getRequestOption(method, data); 
     return this.http.request(url, op1) 
      .catch((err) => { 
       // UnAuthorised, 401 
       if (err.status == 401) { 
        return this.refreshSessionToken().flatMap(t => { 
         let op2 = this.getRequestOption(method, data); 
         return this.http.request(url, op2); 
        }); 
       } 
       throw err; 
      }) 
      .map((response: Response) => { 
       let ret: T = response.json(); 
       return ret; 
      }); 
    } 

    get<T>(url: string): Observable<T> { 
     return this.getApiResponse<T>(url, RequestMethod.Get); 
    } 

    post<T, R>(url: string, body: T): Observable<R> { 
     return this.getApiResponse<R>(url, RequestMethod.Post, body); 
    } 

    put<T, R>(url: string, body: T): Observable<R> { 
     return this.getApiResponse<R>(url, RequestMethod.Put, body); 
    } 

    delete<T>(url: string): Observable<T> { 
     return this.getApiResponse<T>(url, RequestMethod.Delete); 
    } 
} 

DataService.ts

import { Injectable } from '@angular/core'; 
    import { Observable } from 'rxjs/Observable'; 
    import { User } from './User'; 
    import { InterceptedHttp } from './http.interceptor'; 

    @Injectable() 
    export class DataService { 
     constructor(private apiHandler: InterceptedHttp) { } 

     getAll(): Observable<User[]> { 
      return this.apiHandler.get<User[]>('http://mocker.egen.io/users'); 
     } 
    } 

用戶。TS

export class User { 
     id?: number; 

     firstName?: string; 

     lastName?: string; 
    } 

AppComponent.ts

import { Component } from '@angular/core'; 
    import { DataService } from './user-data.service'; 
    import { User } from './User'; 

    @Component({ 
     selector: 'app-root', 
     templateUrl: './app.component.html', 
     styleUrls: ['./app.component.css'] 
    }) 
    export class AppComponent { 
     title = 'app works!'; 
     users: User[]; 

     constructor(dataService: DataService){ 
     dataService.getAll().subscribe((u) => { 
      this.users = u; 
     }); 
     } 
    } 

app.component.html

<h1> 
    <table> 
    <tr *ngFor="let item of users; let i = index"> 
     <td> {{item.firstName}} </td> 
    </tr> 
    </table> 
</h1> 
+0

我需要說我不是承諾的忠實粉絲,也許是因爲我沒有找到足夠的時間或場景來玩! 我沒有真正理解爲什麼一切都被包裝在一個getApiResponse而不是攔截中...... 它是否像一個單獨的方法,它被觸發到一個靜態端點,以檢查在發送到Api之前該令牌是否仍然有效一個真正的要求? – 39ro

+0

那麼,它明顯的選擇在Angular應用中使用observable和promise。 http.get文章和所有回報承諾...您需要了解如何構建承諾...應該完成這項工作。我給出的例子完全符合你的要求。信不信由你在沒有你知識的情況下使用諾言 – codeSetter

+0

經過幾天的測試我仍然處於相同的情況......我真的不明白你的解決方案,以及何時需要解僱getApiResponse! 這看起來與用於HTTP攔截器的舊邏輯中使用的刷新令牌相同! [GitHub庫 - 刷新令牌邏輯(https://gist.github.com/lucassus/d42069763c81a6e6bc68046793893c2c) 其中一個錯誤的使用溶液'''克隆不上型Observable''' – 39ro

0

我回答了類似的問題here

您無法將克隆的請求傳遞到下一個處理程序。相反,使用HttpClient重新嘗試克隆的請求。

this.http.request(clonedReq).subscribe(......);