1

我有以下身份验证服务:

@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 的响应,则应该启动注销过程。

App模块中的设置如下:

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

这会在Http拦截器需要AuthServiceAuthService需要的地方创建一个循环依赖错误Http

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

我尝试使用forwardRefto inject Httpin AuthService,但这并没有改变任何东西。

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

4

1 回答 1

1

基本上这里的要求是,如果从后端收到任何状态为 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);
    }

}

这解决了循环依赖。

希望有帮助。

于 2017-05-26T11:26:25.000 回答