Angular 角度循环依赖。服务->;国家->;服务如何应对?
更新:(更新位于顶部) 在使用NGXS时,我使用下一种方法重新构建了我的服务/状态: 在类中,调用该服务的对象-不再调用该服务。相反,它发出了一个动作。因此,状态为该操作启动适当的reducer,并调用服务方法renewAccessToken,将refreshttoken作为参数填充。 这是我的好方法 但是。。。我还有一个问题(完全是另一个问题)。 分派操作的类实际上是一个自定义HTTP_拦截器,如果令牌刷新成功,我想发出一个request.clone() 我正在考虑决议。。。欢迎提出建议 初始问题:Angular 角度循环依赖。服务->;国家->;服务如何应对?,angular,ionic-framework,architecture,rxjs,ngxs,Angular,Ionic Framework,Architecture,Rxjs,Ngxs,更新:(更新位于顶部) 在使用NGXS时,我使用下一种方法重新构建了我的服务/状态: 在类中,调用该服务的对象-不再调用该服务。相反,它发出了一个动作。因此,状态为该操作启动适当的reducer,并调用服务方法renewAccessToken,将refreshttoken作为参数填充。 这是我的好方法 但是。。。我还有一个问题(完全是另一个问题)。 分派操作的类实际上是一个自定义HTTP_拦截器,如果令牌刷新成功,我想发出一个request.clone() 我正在考虑决议。。。欢迎提出建议 初始
[ng] WARNING in Circular dependency detected:
[ng] src/app/services/auth.service.ts -> src/app/store/auth/state.ts -> src/app/services/auth.service.ts
我理解这个错误。
但我来这里是想征求你的意见,如何应对。
我应该如何使用最佳实践来改变我的结构
我用的是离子+角度+NGX
我目前的想法是直接从localStorage
获取刷新令牌,而不在AuthService
中注入AuthState
。但我认为这并不是解决这些问题的最佳办法
我的当前代码附在下面:
状态:
import { State, Action, StateContext, Selector, Store } from '@ngxs/store';
import { tap, catchError } from 'rxjs/operators';
import { ImmutableContext } from '@ngxs-labs/immer-adapter';
import { AuthModel } from './model';
import { of } from 'rxjs';
import { JwtHelperService } from '@auth0/angular-jwt';
import { AuthService } from 'src/app/services/auth.service';
import {
TryLogin,
LoginFailed,
LoginSucceess,
TryLogout,
LogoutSuccess
} from 'src/app/pages/login/store/actions';
import { Injectable } from '@angular/core';
import { UiService } from 'src/app/services/ui.service';
import { Unauthorized } from 'src/app/errors/response-errors/unauthorized';
@State<AuthModel>({
name: 'auth',
defaults: {
token: null,
refreshToken: null
}
})
@Injectable()
export class AuthState {
@Selector()
static token(state: AuthModel): string | null {
return state.token;
}
@Selector()
static refreshToken(state: AuthModel): string | null {
return state.refreshToken;
}
@Selector()
static isAuthenticated(state: AuthModel): boolean {
if (state.token) {
const jwtHelper = new JwtHelperService();
if (!jwtHelper.isTokenExpired(state.token)) {
return true;
}
}
return false;
}
constructor(
private authService: AuthService,
private store: Store,
private uiService: UiService
) {}
@Action(TryLogin)
@ImmutableContext()
login({ setState }: StateContext<AuthModel>, { payload }: TryLogin) {
this.uiService.displayLoading();
return this.authService.login(payload).pipe(
catchError(err => {
this.uiService.dismissLoading();
if (err instanceof Unauthorized) {
this.store.dispatch(new LoginFailed());
}
return of(null);
}),
tap((result: any) => {
this.uiService.dismissLoading();
if (result) {
setState((state: AuthModel) => {
state.token = result.token;
state.refreshToken = result.refresh_token;
return state;
});
this.store.dispatch(new LoginSucceess());
}
})
);
}
@Action(TryLogout)
@ImmutableContext()
logout({ setState }: StateContext<AuthModel>, {}: TryLogout) {
setState((state: AuthModel) => {
state.token = null;
state.refreshToken = null;
return state;
});
this.store.dispatch(new LogoutSuccess());
}
}
import { Injectable } from '@angular/core';
import { ApiService } from './api.service';
import { HttpClient } from '@angular/common/http';
import { LoginForm } from '../pages/login/interfaces/login-form';
import { AuthState } from '../store/auth/state';
import { Observable } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class AuthService extends ApiService {
refreshToken$: Observable<string>;
constructor(http: HttpClient) {
super(http);
}
login(credentials: LoginForm) {
console.log('AuthService:login');
return this.post('/login', {
email: credentials.username,
password: credentials.password
});
}
renewAccessToken(): Observable<any> {
console.log('AuthService:renewAccessToken');
return this.post('/renew-access-token', {
refresh_token: AuthState.refreshToken
});
}
}
只需移动刷新令牌和存储在服务中的令牌,这就更有意义了。您是否使用过NGXS?是的,我在项目中使用它,但我也使用单例服务来存储临时数据。我不在staterefreshToken中创建实例属性,因为它不是临时数据。它在身份验证状态下存在很长一段时间,这会将其保存在数据库下的localStorage中。如果确实要保存在状态中,为什么不在状态中创建另一个操作以保存令牌,并且当身份验证服务获取令牌时,可以在状态操作函数中调度该操作,那么您应该能够避免循环依赖。只需将刷新令牌和令牌移动到服务中存储,这更有意义。您是否使用过NGXS?是的,我在项目中使用它,但我也使用单例服务存储临时数据。我不在staterefreshToken中创建实例属性,因为它不是临时数据。它在身份验证状态下存在很长一段时间,这会将其保存在数据库下的localStorage中。如果您真的想保存在状态中,为什么不在状态中创建另一个操作来保存令牌?当身份验证服务获取令牌时,您可以在状态操作函数中调度该操作,那么您应该能够避免循环依赖。