angular - NGRX 7 - 即使在 ngrx/effects 中调度不同类型的新动作时也陷入无限循环
问题描述
我正在尝试在@angular/core 7.1.0 和@ngrx/store 7.0 中实现登录。现在的问题是,当我从我的登录组件调度一个新的登录动作时,它在登录效果中正确侦听,但即使在调度新的 LoginSuccess 动作时,登录动作也会陷入无限循环,直到 LoginFailure 动作发生。(当我停止后端时服务)。
auth.effects.ts
@Effect()
login$: Observable<Action> = this.actions$.pipe(
ofType(AuthActionTypes.LOGIN),
map((action: Login) => action.payload),
switchMap(payload => {
console.log('SwitchMap: Login [Effect]: payload', payload);
return this.authService.login(payload.email, payload.password).pipe(
map((loginResponse: LoginResponse) => {
console.log('loginResponse:', loginResponse);
return new LoginSuccess(loginResponse);
}),
catchError(error => {
console.log(error);
return of(new LoginFailure({ error: error }));
})
);
})
);
@Effect({ dispatch: false })
loginSuccess: Observable<any> = this.actions$.pipe(
ofType(AuthActionTypes.LOGIN_SUCCESS),
map((action: LoginSuccess) => action.payload),
tap((loginResponse: LoginResponse) => {
console.log('Login_Success [Effect]: payload', loginResponse);
localStorage.setItem('accessToken', loginResponse.accessToken);
localStorage.setItem('refreshToken', loginResponse.refreshToken);
localStorage.setItem('user', JSON.stringify(loginResponse.user));
// if (loginResponse.user.isSuperAdmin) {
// this.router.navigate(['/admin/dashboard']);
// } else {
// this.router.navigate(['/dashboard']);
// }
})
);
登录组件.ts
onSubmit() {
// Will triggered only when form is submitted
if (this.loginForm.valid) {
console.log('Form Submitted: values', this.loginPayload);
this.store.dispatch(new Login({ email: this.loginPayload.username, password: this.loginPayload.password }));
this.loginForm.resetForm();
}
}
编辑:新发现 当我返回一个 http 调用(来自 authService)时,可以观察到:
return this.http.put<LoginResponse>('/api/v1/entrance/login', body);
这个错误正在发生(即请求陷入无限循环)。但是,当我通过像下面这样重新调整新的 observable 来伪造 api 时,事实并非如此。
return new Observable<LoginResponse>((observer) => {
if (email === 'superadmin@xyz.com' && password === 'abc123') {
const data: LoginResponse = {
accessToken: 'dadsfjhsjdahlfjh#324jk34h23343kkjlsadsads',
refreshToken: 'jfjsdg-32432-sdf4543-sdff4234-3424-3434',
user: {
email: 'superadmin@xyz.com',
name: 'Superadmin',
isSuperAdmin: true,
id: 1,
isLdapUser: false,
isAdUser: false,
lastSeenAt: new Date().getTime()
}
};
observer.next(data);
} else {
observer.error({ error: 'invalid credentials.' });
}
observer.complete();
});
解决方案
经过大量调试,我终于找到了错误:,它在我的 authorizeRequest 拦截器中。以前我的这个拦截器的代码是:
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return this.store.select('auth').pipe(
switchMap((authState: fromAuth.State) => {
if (authState.user && authState.accessToken) {
const secureReq = req.clone({
headers: req.headers.set('Authorization', 'Bearer ' + authState.accessToken)
});
return next.handle(secureReq);
} else {
return next.handle(req);
}
})
);
}
在这种情况下,每当身份验证状态发生变化时,都会分派新请求,从而导致无限循环。为了解决这个问题,我必须使用take(1) 运算符,
所以我的代码现在变成了:
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return this.store.select('auth').pipe(
take(1),
switchMap((authState: fromAuth.State) => {
if (authState.user && authState.accessToken) {
const secureReq = req.clone({
headers: req.headers.set('Authorization', 'Bearer ' + authState.accessToken)
});
return next.handle(secureReq);
} else {
return next.handle(req);
}
})
);
}
推荐阅读
- javascript - 单元测试检查 React 组件的顺序
- javascript - 如何从一个页面保存多个画布
- wordpress - Woocommerce 产品图片链接到外部会员链接
- java - 如果 TextView 显示特定文本,则将可见性设置为 GONE
- css - 如何在一行中居中 3 列?
- dojo - Dojo gridx 偶尔会以错误的顺序显示行
- html - 具有类内部标题的 div 将包含三个 div 元素
- r - 如何根据以下格式制作索引和拆分列
- facebook - 使用 Ionic 登录 Facebook 时未显示权限
- docker - 在 HTTPS 上运行 docker 服务