2016-11-05 83 views
7

我有@ngrx/store和效果工作正常,但是,我意识到会有很多API调用(在特效中),并且如果其中任何一个返回我应该将用户重定向到登录页面时出现401错误。我的问题是:我不想检查每一个效果,这将是一个相同的东西额外的代码。比方说,比如我有一个像这样的代码:Angular 2,在@ ngrx/effects中捕获401

样品效果

@Effect() getMe$ = this.actions$ 
    .ofType(GET_ME) 
    .map(action => action.payload) 
    .switchMap(payload => this.userService.me() 
     .map(res => ({ type: GET_ME_SUCCESS, payload: res })) 
     .catch(() => Observable.of({ type: GET_ME_FAILURE })) 
    ); 

userService.me()

me(): Observable<User> { 
    return this.apiService.get(`/auth/me`); 
} 

apiService.get()

get(endpoint: string): Observable<any> { 
    return this.http.get(`${this.base}${endpoint}`, this.options()) 
    .map(res => res.json()); 
} 

这很好,但我不知道如何处理API时返回。在这种情况下,我应该在哪里重定向全球用户?我应该为这种情况创建一个动作吗?我应该在哪里派遣那个行动呢?或者我完全错了吗?

任何帮助正确的方向将不胜感激!

回答

12

Http发出的错误将包含status属性(设置为HTTP状态码),如果它们是从服务器接收的错误。

如果您在您的基于HTTP的服务失败操作的错误状态:

@Effect() getMe$ = this.actions$ 
    .ofType(GET_ME) 
    .map(action => action.payload) 
    .switchMap(payload => this.userService.me() 
     .map(res => ({ type: GET_ME_SUCCESS, payload: res })) 
     .catch(error => Observable.of({ 
      type: GET_ME_FAILURE, 
      payload: { errorStatus: error.status } 
     })) 
    ); 

然后,您可以编写一个通用的影响,着眼于所有行动并重定向如果它们包含一个401错误:

@Effect() errorStatus401$ = this.actions$ 
    .map(action => action.payload) 
    .filter(payload => payload && payload.errorStatus === 401) 
    .switchMap(payload => { 
     this.router.navigate(['/login']); 
     return Observable.empty(); 
    }); 

或者,如果您使用@ngrx/router-store

import { go } from '@ngrx/router-store'; 
... 

@Effect() errorStatus401$ = this.actions$ 
    .map(action => action.payload) 
    .filter(payload => payload && payload.errorStatus === 401) 
    .map(payload => go(['/login'])); 

如果有您希望浏览之前执行其他操作,您可以使用concat发出多个动作:

@Effect() errorStatus401$ = this.actions$ 
    .map(action => action.payload) 
    .filter(payload => payload && payload.errorStatus === 401) 
    .switchMap(payload => Observable.concat({ type: 'CLEAR_TOKEN' }, go(['/login']))); 
+0

好吧,这似乎工作,谢谢!如果您不介意,还有一个问题:在导航前有没有办法调用另一个操作(CLEAR_TOKEN)?观察对我来说真的很新鲜。 :) – Andrew

+1

是的,这是可能的。我已经更新了答案。 – cartant