Angular2:解决 Http 拦截工厂和身份验证服务之间的循环依赖关系



我有以下身份验证服务:

@Injectable()
export class AuthService {
  //...
  constructor(private http: Http, private router: Router) {
    //...
  }
  public login(username: string, password: string): Observable<boolean> {
    // perform login
  }
  public logout() {
    // perform cleanup
    this.router.navigateByUrl('/login');
  }
}

以及以下Http拦截器工厂:

@Injectable()
class MyHttpInterceptor extends Http {
  constructor(backend: ConnectionBackend, defaultOptions: RequestOptions, private authService: AuthService) {
    super(backend, defaultOptions);
  }
  request(url: string | Request, options?: RequestOptionsArgs): Observable<Response> {
    return this.intercept(super.request(url, options));
  }
  get(url: string, options?: RequestOptionsArgs): Observable<Response> {
    return this.intercept(super.get(url, options));
  }
  post(url: string, body: string, options?: RequestOptionsArgs): Observable<Response> {
    return this.intercept(super.post(url, body, this.getRequestOptionArgs(options)));
  }
  put(url: string, body: string, options?: RequestOptionsArgs): Observable<Response> {
    return this.intercept(super.put(url, body, this.getRequestOptionArgs(options)));
  }
  delete(url: string, options?: RequestOptionsArgs): Observable<Response> {
    return this.intercept(super.delete(url, options));
  }
  getRequestOptionArgs(options?: RequestOptionsArgs): RequestOptionsArgs {
    if (options == null) {
      options = new RequestOptions();
    }
    if (options.headers == null) {
      options.headers = new Headers();
    }
    // add headers required by our backend
    return options;
  }
  intercept(observable: Observable<Response>): Observable<Response> {
    return observable.catch((err, source) => {
      if (err.status == 401) {
        this.authService.logout();
        return Observable.empty();
      } else {
        return Observable.throw(err);
      }
    });
  }
}
export function myHttpInterceptorFactory(backend: ConnectionBackend, options: RequestOptions, authService: AuthService): MyHttpInterceptor {
  return new MyHttpInterceptor(backend, options, authService);
}

基本上,这里的要求是,如果从状态为 401 的后端收到任何响应,则应启动注销过程。

应用模块中的设置如下:

@NgModule({
  imports: [
    HttpModule,
    //...
  ],
  declarations: [
    AppComponent,
    //...
  ],
  providers: [
    {
      provide: Http,
      useFactory: myHttpInterceptorFactory,
      deps: [XHRBackend, RequestOptions, AuthService]
    },
    AuthService,
    //...
  ],
  bootstrap: [AppComponent]
})
export class AppModule {
}

这会产生循环依赖错误,其中Http拦截器需要AuthService,但AuthService需要Http

Error: Provider parse errors:
Cannot instantiate cyclic dependency! Http: in NgModule AppModule in ./AppModule

我尝试使用forwardRefAuthService中注入Http,但这并没有改变任何事情。

关于如何重组的任何帮助都会很棒。

基本上,这里的要求是,如果从状态为 401 的后端收到任何响应,则应启动注销过程。

如果目标是以特定的方式处理HTTP错误,那么我会这样做:我不会扩展HTTP服务,而是为我的服务创建一个基类来扩展处理重复的HTTP函数,例如提取数据或处理错误。 它看起来像这样:

import { Response } from '@angular/http';
import { Observable } from 'rxjs/Observable';
export class HttpServiceBase {
    constructor(private authSvc: AuthService ) { }
    extractData(res: Response) {
        const body = res.json();
        return body || {};
    }
    handleError(error: Response | any) {
        switch (error.status) {
            .... //other cases
            case 401:
               this.authSvc.logout();
            default:
                //default handling
        }
    }
}

然后像这样使用它:

@Injectable()
export class SomeService extends HttpServiceBase {
    constructor(
        authSvc: AuthService,
        private http: AuthHttp
    )
    {
        super(authSvc);
    }

    sampleCall() {
        return this.http.get(...)
            .map(this.extractData)
            .catch(this.handleError);
    }
}

这解决了周期性依赖性问题。

希望有帮助。

相关内容

  • 没有找到相关文章

最新更新