簡體   English   中英

使用攔截器在Angular 4.3中使用新標頭重試Http請求

[英]Retry Http request with new headers in Angular 4.3 using Interceptor

如何使用新的標頭處理克隆的請求?

我正在嘗試使用第一個請求失敗后生成的新令牌在新的攔截器中執行克隆的請求!

  • 如果錯誤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),為什么?!

我嘗試了其他方法來刷新JWT,但對於我來說似乎不起作用,如何處理它又有幫助嗎?

謝謝!

我期望得到什么結果?

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

類似問題:

HTTP攔截刷新,智威湯遜令牌

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

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

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');
        }
    }

User.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>

這是我使用最新版本的Angular(7.0.0)和rxjs(6.3.3)的解決方案。 希望能幫助到你。

export class SessionRecoveryInterceptor implements HttpInterceptor {
  constructor(
    private readonly store: StoreService,
    private readonly sessionService: AuthService
  ) {}

  private _refreshSubject: Subject<any> = new Subject<any>();

  private _ifTokenExpired() {
    this._refreshSubject.subscribe({
      complete: () => {
        this._refreshSubject = new Subject<any>();
      }
    });
    if (this._refreshSubject.observers.length === 1) {
      // Hit refresh-token API passing the refresh token stored into the request
      // to get new access token and refresh token pair
      this.sessionService.refreshToken().subscribe(this._refreshSubject);
    }
    return this._refreshSubject;
  }

  private _checkTokenExpiryErr(error: HttpErrorResponse): boolean {
    return (
      error.status &&
      error.status === 401 &&
      error.error &&
      error.error.message === "TokenExpired"
    );
  }

  intercept(
    req: HttpRequest<any>,
    next: HttpHandler
  ): Observable<HttpEvent<any>> {
    if (req.url.endsWith("/logout") || req.url.endsWith("/token-refresh")) {
      return next.handle(req);
    } else {
      return next.handle(req).pipe(
        catchError((error, caught) => {
          if (error instanceof HttpErrorResponse) {
            if (this._checkTokenExpiryErr(error)) {
              return this._ifTokenExpired().pipe(
                switchMap(() => {
                  return next.handle(this.updateHeader(req));
                })
              );
            } else {
              return throwError(error);
            }
          }
          return caught;
        })
      );
    }
  }

  updateHeader(req) {
    const authToken = this.store.getAccessToken();
    req = req.clone({
      headers: req.headers.set("Authorization", `Bearer ${authToken}`)
    });
    return req;
  }
}

在這里回答了類似的問題。 您也可以在這里閱讀我的文章,以了解代碼。

在這里回答了類似的問題

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

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM