我有多个相互依赖的提供者(实际上有HTTP Interceptor和2个提供者)。在拦截器中,我通过Injector处理循环依赖:
this.injector.get(AuthProvider).authToken
这个技巧并不适用于提供商。我有AuthProvider和RestaurantProvider。如果我传播的方法应该是看起来像:
export class RestaurantProvider {
....................
auth(email: string, password: string): Observable<{ token: string }> {
return this.http
.post<responseFormat>(environment.api + "/restaurant/auth", {
email: email,
password: password
})
.map((res: responseFormat) => res.data as { token: string });
}
....................
restaurantImageAdd(image: string): Promise<FileUploadResult> {
let options: FileUploadOptions = {
fileKey: "images",
chunkedMode: false
//params: {} //body params
};
let token = this.authProvider.authToken;
if (token) {
options.headers = {
Authorization: "Bearer " + token
};
}
const fileTransfer: FileTransferObject = this.transfer.create();
return fileTransfer.upload(
image,
environment.api + "/restaurant/images",
options
);
}
....................
}
export class AuthProvider {
login(email: string, password: string): Promise<boolean | string> {
return new Promise((resolve, reject) => {
this.restaurantProvider.auth(email, password).subscribe(
res => {
if (res.hasOwnProperty("token")) {
this.setAuthToken(res.token).then(() => {
this.events.publish("login");
resolve(true);
});
}
},
err => {
reject(err);
}
);
});
}
}
&#13;
并且:
如您所见,RestaurantProvider使用AuthProvider相互依赖。因此它导致循环依赖...注射器没有处理这个(不知道为什么)。我的目的是使用SkipSelf或forwardRef,但没有一个会导致任何积极的结果。可能我用错了或者我不能在这种情况下使用它们...目前我发现的唯一解决方法是将auth方法从RestaurantProvider移动到AuthProvider。
无论如何,我只是想问一下你们是如何处理循环依赖的?欢迎任何想法
答案 0 :(得分:0)
正如@Fussel在评论中提到的,您可以使用第三个服务,或从另一个服务中排除其中一个服务(例如AuthProvider
),并将所有必要的数据从组件传递给此服务,如下所示:
<强> RestaurantProvider 强>
// add 'token' as one of parameters
restaurantImageAdd(image: string, token: any): Promise<FileUploadResult> {
let options: FileUploadOptions = {
fileKey: "images",
chunkedMode: false
//params: {} //body params
};
if (token) {
options.headers = {
Authorization: "Bearer " + token
};
}
const fileTransfer: FileTransferObject = this.transfer.create();
return fileTransfer.upload(
image,
environment.api + "/restaurant/images",
options
);
}
<强> AnyComponent 强>
...
export class AnyComponent {
...
constructor(private _authProvider: AuthProvider,
private _restaurantProvider: RestaurantProvider) {
_restaurantProvider.restaurantImageAdd('imageUrl', _authProvider.authToken) // pass 'token' as the second parameter
}
}
答案 1 :(得分:0)
为此添加一些代码。
TokenService不需要HttpClient,它不会超过这个。
@Injectable()
export class TokenService {
auth_token_key: string = "auth_token";
constructor() {
}
get token(): string {
return localStorage.getItem(this.auth_token_key);
}
set token(token: string) {
localStorage.setItem(this.auth_token_key, token);
}
}
简化的拦截器可能如下所示。
@Injectable()
export class AuthInterceptor implements HttpInterceptor {
constructor(private tokenService: TokenService) {}
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
if(this.tokenService.token) {
request = request.clone({
setHeaders: {
Authorization: `Bearer ${this.tokenService.token}`
}
});
}
return next.handle(request);
}
}
AuthService有点像这样
@Injectable()
export class AuthService {
private apiUrl: string = environment.apiUrl+'/auth';
private headers = new HttpHeaders({'Content-Type': 'application/json'});
constructor(private http: HttpClient, private tokenService: TokenService) {}
login(user: String, password: String): Promise<any> {
return this.http.post(`${this.apiUrl}/login`, JSON.stringify({'login': user, 'password': password}), {headers: this.headers}).toPromise().then((t: Token) => {
this.tokenService.token = t.token;
return true;
});
}
正如我所说的,在我的情况下,AuthInterceptor用于子模块,而TokenService由app.module提供,但这没有循环依赖性错误,对我来说至少这似乎是一个干净的解决方案而不使用注入器。