Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
861 views
in Technique[技术] by (71.8m points)

angular - HttpInterceptor->Service->HttpClient Cyclic Dependency

So I have my authentication service, AuthService, that basically has two methods, one that gets a new token from the server, given a username and a password, and one that retrieves the current stored token and refreshes the tokens during the process when necessary. Both obviously rely on HttpClient. That is, AuthService has a dependency on HttpClient. Let's keep that in mind.

Another "service" is an HttpInterceptor that I want to intercept all outgoing requests other than those made by AuthService to add the Authorization header (it's getting dirty now). And to make up that header, we need a token, which we get from AuthService. That is, AuthInterceptor (the name of my interceptor) has a dependency on AuthService. And as far as I know, HttpClient has a dependency on all HTTP_INTERCEPTORS.

So the scenario is as follows: Cyclic Dependency

Any ideas or suggestions on how to break that circle? Is there any way to make AuthService's HttpClient independent of AuthInterceptor? Or is it a bad idea? (Another third function will be added to AuthService for logging the user out, whose requests shall be intercepted and have the Authorization header added to them as well)

So far I found a similar issue but the workaround suggested there doesn't solve my problem, now I get infinite recursion during the bootstrapping process before any requests are sent. I've handled the case of login and token refresh requests being intercepted to avoid this so this is not the issue here as far as I know. Here's a plunk with an overview of my code.

Excerpt from the plunk:

@Injectable()
export class AuthInterceptor implements HttpInterceptor {
  private auth: AuthService;

  constructor(inj: Injector) {
    this.auth = inj.get(AuthService);
  }

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    // Ignore if login or refresh request
    if (req.url.includes('login')) {
      return next.handle(req);
    }

    console.log('Intercepting request...');
    return this.auth.getToken().map(token => {
      const authHeader = 'Bearer ' + token;
      const authReq = req.clone({setHeaders: {Authorization: authHeader}});
      return authReq;
    }).concatMap(newReq => next.handle(newReq));
  }
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Try setting this.auth with a timeout:

constructor(private injector: Injector) {
  setTimeout(() => {
    this.auth = this.injector.get(AuthService);
  })
}

The bug report you have linked to has since been updated, with an alternative workaround (retrieving AuthService in the intercept function / and not setting it in the constructor): https://github.com/angular/angular/issues/18224#issuecomment-316957213


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...