Can someone explain me how the interceptor catch error function with providers?

强颜欢笑 提交于 2019-12-11 18:41:12

问题


I've implemented my interceptor where I control error status, and I am confused about where should i catch errors or what should I use : .of, throw or empty ?

 intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    if (!req.url.includes('auth')) {
      console.log("NO INCLUDE auth ")
      let getTsObs = Observable.fromPromise(this.storage.get('token'));
      const tokenObservable = getTsObs.map(token => {
        return req = req.clone({
          setHeaders: {
            Authorization: `Bearer ${token}`
          }
        });
      });
      return tokenObservable.flatMap((req) => {
        return next.handle(req)
          .do((event: HttpEvent<any>) => {
            if (event instanceof HttpResponse) {
              // do stuff to the response here
            }
          }, error => {
            if (error.status === 403) {
              this.cleanApp();                  
              return Observable.throw(error);
            }
            else if(error.status === 404 ||error.status === 500){
              return Observable.of([]);
            }else {                
              return Observable.throw(error);                  
            }
          })
      })
    }
    else {
      console.log("INCLUDE auth")
      let clone = req.clone({
        setHeaders: {
          Accept: `application/json`,
          'Content-Type': `application/json`
        }
      });
      return next.handle(clone);
    }
  }

 private cleanApp() {  
    this._us.removeStorageTokenExpired();
    let nav = this.app.getActiveNav();
    nav.setRoot('Login');  
  }

I want to send to Login when error is 403 and cancel the next calls, for example if I am using forkjoin .

My backend return error 404 and 500 with result [], when this call doesnt return anything however I dont know if this is the best way to return that in case the call is ok but it doesnt return any row. For this reason you can see that my code return Observable.of([]) to it doesnt cancel forkjoins,for example.

Now my provider is :

public listGroups(action, search, page): Observable<any> {
    let url = URL_SERVICIOS + '/users/groups?action=' + action;
    if (action === "all") {
      url = url + '&search=' + search + '&page=' + page;
    }
    return this.http
      .get(url)
      .map(res => {
        if (action === "all") {
          return res;
        } else {
          return res['result'];
        }
      })
      .catch(error => {
        //if (error.status === 404||error.status===500)
          //return Observable.of([]);
        return Observable.of([]); 
      })
  }

The first time, when i uncommented 2 first lines i get this error :

ERROR TypeError: You provided 'undefined' where a stream was expected. You can provide an Observable, Promise, Array, or Iterable.

I've solved this error , commenting the 2 first lines.

Could someone explain me what is the best way to handle error with interceptor and providers correctly ?

On the other hand , I have a cleanApp to clean storage when error is 403, but if I have a forkjoin with 3 calls , it'll be call 3 times and it occurss an error. how can i achieve that to do that 1 time only .

Thank you


回答1:


I would simplify the interceptor, and handle errors with a Guard service. Also, I would avoid requesting the token from local storage. I would store it, pass it in memory, and retrieve it within an AuthService.

@Injectable()
export class TokenInterceptor implements HttpInterceptor {
  constructor(public _auth: AuthService) {}
  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    if (this.auth.authToken) {
      console.log('JWT', this.auth.authToken)
      request = request.clone({
        setHeaders: {
          Authorization: `Bearer ${this.auth.authToken}`,
        },
      })
    }
    return next.handle(request)
  }
}

Put this as a provider in your app.module

    {
      provide: HTTP_INTERCEPTORS,
      useClass: TokenInterceptor,
      multi: true,
    },
@Injectable()
export class AuthGuard implements CanActivate {
  constructor(
    private _router: Router,
    private _auth: AuthService
  ) {}
  canActivate(
    route: ActivatedRouteSnapshot,
    state: RouterStateSnapshot
  ): Observable<boolean> | boolean {
    const token = auth.authToken
    if (!token) {
      // Session Expired
      this._router.navigate(['/login'])
    }
    return true
  }
}

  {
    path: '',
    canActivate: [AuthGuard],
    component: LayoutMainComponent
  },
@Injectable()
export class AuthService {
  currentUser$: BehaviorSubject<any> = new BehaviorSubject<any>(null)

  public authToken: String

  constructor() {
    // save auth token
    this.currentUser$.pipe(filter(user => !!user)).subscribe(user => {
      this.authToken = user.token
    })


来源:https://stackoverflow.com/questions/54852173/can-someone-explain-me-how-the-interceptor-catch-error-function-with-providers

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!