处理Angular 4 +

时间:2018-04-09 08:44:25

标签: angular

我有多个相互依赖的提供者(实际上有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;
&#13;
&#13;

并且:

如您所见,RestaurantProvider使用AuthProvider相互依赖。因此它导致循环依赖...注射器没有处理这个(不知道为什么)。我的目的是使用SkipSelfforwardRef,但没有一个会导致任何积极的结果。可能我用错了或者我不能在这种情况下使用它们...目前我发现的唯一解决方法是将auth方法从RestaurantProvider移动到AuthProvider。

无论如何,我只是想问一下你们是如何处理循环依赖的?欢迎任何想法

2 个答案:

答案 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提供,但这没有循环依赖性错误,对我来说至少这似乎是一个干净的解决方案而不使用注入器。