【问题标题】:angular http interceptor repeat request doesn't work角度http拦截器重复请求不起作用
【发布时间】:2019-12-12 22:06:49
【问题描述】:

我正在做 Angular 8 应用程序,我正在尝试实现 Angular http 拦截器重复请求。我想拦截我对 WebAPI 的所有 UI 请求,当我的令牌过期时,刷新令牌并召回所有被拒绝的请求。 我实现了代码:

import { Inject, Injectable, Injector } from '@angular/core';
import {
    HttpInterceptor,
    HttpRequest,
    HttpResponse,
    HttpHandler,
    HttpEvent,
    HttpErrorResponse
} from '@angular/common/http';

import { Observable, throwError, from, Subject } from 'rxjs';
import { tap, map, catchError } from 'rxjs/operators';

import { StorageSvc } from '../factories/storageSvc';
import { SysSettings } from '../constant/sysSettings';
import { SingletonRootClass } from '../../../src/app/shared/singleton-root';
import { AuthService } from './authService';
import { Router } from '@angular/router';

@Injectable()

export class InterceptService implements HttpInterceptor {

    refreshTokenInProgress = false;

    tokenRefreshedSource = new Subject();
    tokenRefreshed$ = this.tokenRefreshedSource.asObservable();


    constructor(@Inject(StorageSvc) public storageSvc: any,
                @Inject(AuthService) public authService: any,
                private router: Router,
                private injector: Injector
    ) { }

    addAuthHeader(request) {
        const authData = this.storageSvc.retrieve('authorizationData');
        const language = authData && authData.profile
            ? { languageCode: authData.profile.laguageCode, regionCode: authData.profile.regionCode }
            : this.getDefaultLanguage();

        const headers = {
            'Accept-Language': this.buildAcceptLanguageHeader(language.languageCode, language.regionCode),
            'NotificationConnectionId': SysSettings.NotifyConnectionId
        };

        if (authData) {
            headers['Authorization'] = 'Bearer ' + authData.token;
            headers['UserName'] = authData.userName;
        }

        request = request.clone({
            setHeaders: headers
        });

        return request;
    }

    // intercept request and add token
    intercept(request: HttpRequest<any>, next: HttpHandler): Observable<any> {
        request = this.addAuthHeader(request);

        // Handle response
        return next.handle(request).pipe(
            map((event: HttpEvent<any>) => {
                if (event instanceof HttpResponse) {
                    console.log('event--->>>', event);
                }
                return event;
            }),
                catchError((error: HttpErrorResponse) => {
                    if (error.status === 401) {
                        return this.refreshToken()
                            .switchMap(() => {
                                request = this.addAuthHeader(request);
                                return next.handle(request);
                            })
                            .catch(() => {
                                this.authService.logOut();
                                this.router.navigate(['/login']);
                            });
                    }

                    return throwError(error);
                })
        );

    }

    refreshToken() {
        if (this.refreshTokenInProgress) {
            return new Observable(observer => {
                this.tokenRefreshed$.subscribe(() => {
                    observer.next();
                    observer.complete();
                });
            });
        } else {
            this.refreshTokenInProgress = true;

            return this.authService.refreshToken()
                .do(() => {
                    this.refreshTokenInProgress = false;
                    this.tokenRefreshedSource.next();
                });
        }
    }

    sleep(ms = 0) {
        return new Promise(r => setTimeout(r, ms));
    }
    getDefaultLanguage() {
        // const savedLanguage = this.storageSvc.retrieve('language');
        const savedLanguage = SingletonRootClass.getInstance().defaultLang;
        // Region code not used for now
        const language = { languageCode: savedLanguage ? savedLanguage : 'en', regionCode: 'CA' };
        return language;
    }

    buildAcceptLanguageHeader(languageCode, regionCode) {
        return languageCode + '-' + regionCode + ',' + languageCode + ';' + 'q=0.8,en;q=0.6';
    }
}

但我无法自动回忆被拒绝的请求。在我的截图上:GetNotifications、GetNotificationTypes 和 GetEventTypes

任何人都可以推荐拦截器的角度解决方案来召回在刷新令牌时同时被拒绝的所有请求吗? 谢谢你

【问题讨论】:

    标签: angular typescript rxjs


    【解决方案1】:

    试试这个

      isRefreshingToken: boolean = false;
      tokenSubject: Subject<boolean> = new Subject<boolean>();
    
      intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        return next.handle(request).pipe(
          catchError((err, source) => {
            if (err instanceof HttpErrorResponse) {
              if (err.status === 401) {
                return this.handle401Error(request, next);
              } 
            }
            return observableThrowError(err.error);
          })
        );
      }
    
      private handle401Error(request: HttpRequest<any>, next: HttpHandler): Observable<any> {
        this.requestRefreshToken();
        return this.tokenSubject.pipe(
          take(1),
          switchMap(token => {
            return next.handle(request);
          }));
    
      }
    
      private requestRefreshToken() {
        if (!this.isRefreshingToken) {
          this.isRefreshingToken = true;
          this.authService.refreshToken()
            .subscribe(user => {
              if (user) {
                this.tokenSubject.next(user);
              }
              this.isRefreshingToken = false;
            }, (err: HttpErrorResponse) => {
              this.authService.logout()
              this.isRefreshingToken = false; 
              return observableThrowError(err);
            }, () => {
            });
        }
      }
    

    【讨论】:

      【解决方案2】:

      适用于 Angular 7 的拦截解决方案:

      auth-interceptor.ts

      import { Inject, Injectable, Injector } from '@angular/core';
      import {
          HttpInterceptor,
          HttpRequest,
          HttpResponse,
          HttpHandler,
          HttpEvent,
          HttpErrorResponse
      } from '@angular/common/http';
      
      import { Observable, throwError, from, Subject, BehaviorSubject } from 'rxjs';
      import { catchError, filter } from 'rxjs/operators';
      
      import { StorageSvc } from '../factories/storageSvc';
      import { SysSettings } from '../constant/sysSettings';
      import { SingletonRootClass } from '../../../src/app/shared/singleton-root';
      import { AuthService } from './authService';
      import { Router } from '@angular/router';
      
      import { take, switchMap  } from 'rxjs/operators';
      
      @Injectable()
      
      export class InterceptService implements HttpInterceptor {
      
          private isRefreshing = false;
          private refreshTokenSubject: BehaviorSubject<any> = new BehaviorSubject<any>(null);
      
          constructor(@Inject(StorageSvc) public storageSvc: any,
                      @Inject(AuthService) public authService: any,
                      private router: Router,
                      private injector: Injector
          ) { }
      
          addAuthHeader(request) {
              const authData = this.storageSvc.retrieve('authorizationData');
              const language = authData && authData.profile
                  ? { languageCode: authData.profile.laguageCode, regionCode: authData.profile.regionCode }
                  : this.getDefaultLanguage();
      
              const headers = {
                  'Accept-Language': this.buildAcceptLanguageHeader(language.languageCode, language.regionCode),
                  'NotificationConnectionId': SysSettings.NotifyConnectionId
              };
      
              if (authData) {
                  console.log("token:" + 'Bearer ' + authData.token);
                  headers['Authorization'] = 'Bearer ' + authData.token;
                  headers['UserName'] = authData.userName;
              }
      
              request = request.clone({
                  setHeaders: headers
              });
      
              return request;
          }
      
      
          intercept(request: HttpRequest<any>, next: HttpHandler): Observable<any> {
      
              request = this.addAuthHeader(request);
      
              return next.handle(request).pipe(catchError(error => {
                  if (error instanceof HttpErrorResponse && error.status === 401) {
                      return this.handle401Error(request, next);
                  } else {
                      return throwError(error);
                  }
              }));
          }
      
          private handle401Error(request: HttpRequest<any>, next: HttpHandler) {
              if (!this.isRefreshing) {
                  this.isRefreshing = true;
                  this.refreshTokenSubject.next(null);
      
                  return this.authService.refreshToken().pipe(
                      switchMap((token: any) => {
                          this.isRefreshing = false;
                          this.refreshTokenSubject.next(token.access_token);
                          request = this.addAuthHeader(request);
                          return next.handle(request);
                      }));
      
              } else {
                  return this.refreshTokenSubject.pipe(
                      filter(token => token != null),
                      take(1),
                      switchMap(jwt => {
                          request = this.addAuthHeader(request);
                          return next.handle(request);
                      }));
              }
          }
      
          sleep(ms = 0) {
              return new Promise(r => setTimeout(r, ms));
          }
          getDefaultLanguage() {
              // const savedLanguage = this.storageSvc.retrieve('language');
              const savedLanguage = SingletonRootClass.getInstance().defaultLang;
              // Region code not used for now
              const language = { languageCode: savedLanguage ? savedLanguage : 'en', regionCode: 'CA' };
              return language;
          }
      
          buildAcceptLanguageHeader(languageCode, regionCode) {
              return languageCode + '-' + regionCode + ',' + languageCode + ';' + 'q=0.8,en;q=0.6';
          }
      }
      

      authService.ts:

      import { Inject, Injectable } from '@angular/core';
      import { HttpClient, HttpHeaders  } from '@angular/common/http';
      import { JwtHelperService } from '@auth0/angular-jwt';
      
      import * as $ from 'jquery';
      
      import { StorageSvc } from '../factories/storageSvc';
      import { CrudService } from './crudService';
      // import {NotifyHub} from '../../../src/app/angularJS-upgraded-providers';
      import { SysSettings } from '../constant/sysSettings';
      import { Authentication } from '../model/authentication.model';
      import { SingletonRootClass } from '../../../src/app/shared/singleton-root';
      import { Router } from '@angular/router';
      
      import { tap } from 'rxjs/operators';
      
      @Injectable()
      export class AuthService {
          private serviceBase = SysSettings.WebServiceURL;
          private refreshInProgress = false;
          private refreshPromises = [];
          public authentication = new Authentication();
      
          constructor(
              private httpClient: HttpClient,
              private storageSvc: StorageSvc,
              private crudSvc: CrudService,
              private router: Router,
              // @Inject(NotifyHub) private notifyHub  //TODO
          ) {
      
          }
      
      
          refreshToken() {
              const authData = this.storageSvc.retrieve('authorizationData');
              const data = 'grant_type=refresh_token&refresh_token=' + authData['refreshToken'] +
                  '&client_id=' + SysSettings.clientId;
      
              return this.httpClient.post(this.serviceBase + 'token', data,
                  { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }).pipe(tap((respData) => {
                  const response: any = respData;
                  const oldAuthData = this.storageSvc.retrieve('authorizationData');
                  const loginTime = oldAuthData['loginTime'] ? new Date(oldAuthData['loginTime']) : new Date();
                  const newAuthData = {
                      token: response.access_token,
                      userId: response.userName,
                      userName: response.userName,
                      refreshToken: response.refresh_token,
                      useRefreshTokens: true,
                      loginTime: loginTime
                  };
                  if (oldAuthData && oldAuthData['profile']) {
                      newAuthData['profile'] = oldAuthData['profile'];
                  }
                  this.storageSvc.store('authorizationData', newAuthData);
              }));
          }
      
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-02-02
        • 2021-08-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-05-04
        相关资源
        最近更新 更多