当组件调用多个API时,仅调用拦截器一次

3

我在一个组件中使用了多个API,在token过期拦截器运行时,会多次执行。例如,如果我在单个组件中有4个GET API,则在token过期时会运行4次拦截器。

以下是拦截器的代码

my.httpInterceptor.ts

import {
  Injectable
} from "@angular/core";
import {
  tap
} from "rxjs/operators";
import {
  ToastyService,
  ToastOptions
} from 'ng2-toasty';
import {
  Router
} from "@angular/router";
import {
  _throw
} from 'rxjs/observable/throw';
import 'rxjs/add/operator/do';
import 'rxjs/Observable';
import {
  HttpRequest,
  HttpHandler,
  HttpEvent,
  HttpInterceptor,
  HttpResponse,
  HttpErrorResponse,
  HttpHeaders
} from "@angular/common/http";
import {
  Observable
} from "rxjs/Observable";

@Injectable()
export class MyInterceptor implements HttpInterceptor {
  constructor(private router: Router, private toastyService: ToastyService, ) {}

  //function which will be called for all http calls
  intercept(
    request: HttpRequest < any > ,
    next: HttpHandler
  ): Observable < HttpEvent < any >> {
    //how to update the request Parameters
    if (JSON.parse(localStorage.getItem('userDetails'))) {
      let authToken = JSON.parse(localStorage.getItem('userDetails'));
      if (authToken.currentUserToken != null) {
        const authReq = request.clone({
          headers: new HttpHeaders({
            'Content-Type': 'application/json',
            'Authorization': 'Bearer' + authToken.currentUserToken
          })
        });
        return next.handle(authReq)
          .catch((err) => {
            if (err) {
              let errorCodes = [404, 500, 422, 412, 424, 409];
              if (errorCodes.includes(err.status)) {
                let toastOptions: ToastOptions = {
                  title: "Error",
                  msg: "Error",
                  showClose: true,
                  timeout: 5000,
                  theme: 'default'
                };
                toastOptions.msg = err.error.errors.name;
                this.toastyService.error(toastOptions);
              }
              if (err.status === 401) {
                this.router.navigate(['/']).then((nav) => {
                  // debugger;
                  if (nav) {
                    if (this.router.url === '/') {
                      setTimeout(() => {
                        let toastOptions: ToastOptions = {
                          title: "Session Expired",
                          msg: "Please login again to access",
                          showClose: true,
                          timeout: 5000,
                          theme: 'default',
                        }
                        // toastOptions.msg = "Session Expired";
                        this.toastyService.error(toastOptions);
                      });
                    }
                  }
                });
              }
              return _throw(err.message);
            }
          });
      }
    } else {
      const updatedRequest = request.clone({
        headers: new HttpHeaders({
          'Content-Type': 'application/json',
        })
      });
      return next.handle(updatedRequest)
    }
  }


}

如何避免多次调用拦截器。
1个回答

1
拦截器会对所有发出的HTTP请求进行调用。但是,您可以过滤您想要应用逻辑的请求URL:
@Injectable()
export class MyInterceptor implements HttpInterceptor {
  constructor(private router: Router, private toastyService: ToastyService) {
  }

  //The API you want to intercept its requests (you could take it from a global constants file)
  API_URL = "http://www.example.com/host/to/intercept";

  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {

    //only get the token from localStorage when the request points to the API that needs authorization
    if (request.url === this.API_URL) {
      let userDetails = localStorage.getItem('userDetails');
      if (userDetails != null) {
        let authToken = JSON.parse(userDetails);
        if (authToken.currentUserToken != null) {
          const authReq = request.clone({
            headers: new HttpHeaders({
              'Content-Type': 'application/json',
              'Authorization': 'Bearer' + authToken.currentUserToken
            })
          });
          return next.handle(authReq)
          .catch((err) => {
            if (err) {
              let errorCodes = [404, 500, 422, 412, 424, 409];
              if (errorCodes.includes(err.status)) {
                let toastOptions: ToastOptions = {
                  title: "Error",
                  msg: "Error",
                  showClose: true,
                  timeout: 5000,
                  theme: 'default'
                };
                toastOptions.msg = err.error.errors.name;
                this.toastyService.error(toastOptions);
              }
              if (err.status === 401) {
                this.router.navigate(['/']).then((nav) => {
                  // debugger;
                  if (nav) {
                    if (this.router.url === '/') {
                      setTimeout(() => {
                        let toastOptions: ToastOptions = {
                          title: "Session Expired",
                          msg: "Please login again to access",
                          showClose: true,
                          timeout: 5000,
                          theme: 'default',
                        }
                        // toastOptions.msg = "Session Expired";
                        this.toastyService.error(toastOptions);
                      });
                    }
                  }
                });
              }
              return _throw(err.message);
            }
          });
        }
      } else {
        const updatedRequest = request.clone({
          headers: new HttpHeaders({
            'Content-Type': 'application/json',
          })
        });
        return next.handle(updatedRequest);
      }
    }
  }
}

请问,您能详细说明一下功能吗? - vinuta
基本上,您需要按URL过滤需要授权(指向经过身份验证的API)的外向请求,并仅将令牌添加到这些请求中。对于发送到另一个API的请求,不会进行令牌检查。 - lsantamaria

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接