【问题标题】:How to wait for a http request to finish from another component?如何等待来自另一个组件的 http 请求完成?
【发布时间】:2021-07-05 18:16:39
【问题描述】:

组件控制器对GetData的调用过早,我希望它等待识别结束后再触发。

页面加载时,有调用服务器进行识别:

return this.http.get<AuthInfo>('.../Auth/login').pipe(
  map((authInfo: AuthInfo) => {
    // ... authentification completed
    return authInfo;
  }),
);

然后,他们将能够从其他几个组件调用服务器:(使用之前提供的 JWT 令牌)

this.serviceA.methodB().subscribe(
  result => { ... }
)
methodB(): Observable<any> {
  return this.http.get<any>('.../Data/GetData').pipe(
    map(result => {
            ...
      return result;
    }),
  );
}

我希望只有在识别完成后才调用methodB。

所以如果调用任何方法,如果识别过程没有完成,它必须能够暂停。

这里的难点在于methodB是在登录方法执行期间或之后从其他地方调用的。

RxJs 可以做到这一点吗?

【问题讨论】:

  • 我认为您需要一个共享服务来存储身份识别状态(作为Observable 或Subject)

标签: javascript angular rxjs


【解决方案1】:

您可以在BehaviorSubject 中公开身份验证信息:

class AuthenticationService {
  private subject = new BehaviorSubject(null);
  public info = subject.asObservable();

  authenticate() {
    this.http.get<AuthInfo>('.../Auth/login').subscribe(x => this.subject.next(x), e => this.subject.error(e))
  }
}

在您的应用中需要的任何地方(例如:登录按钮上)致电authenticate

那么我建议您使用拦截器,以确保请求在发送之前经过身份验证:

class AuthenticationInterceptor {
  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return authenticationService.info.pipe(
      tap(x => /* If you need to attach the JWT to an HTTP header, do it there */),
      switchMap(() => next.handle(req))
    )
  }
}

【讨论】:

    【解决方案2】:

    您可以在某种服务中将 JWT-Token 作为ReplaySubject 提供(如果您有的话,可能是您的AuthenticationService)。然后您可以使用HttpInterceptor 拦截来自您的应用程序的每个 HttpRequest 并将 JWT 令牌添加到请求标头中。

    class AuthenticationService {
      public token = new ReplaySubject<string>(1)
    
      public login() {
        // your login logic here
        this.token.next(theToken)
      }
    }
    
    class AuthInterceptor implements HttpInterceptor {
      constructor (private authService: AuthService) {}
    
      intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        return this.authService.token.pipe(
          mergeMap(token => {
            req = req.clone({
              headers: new HttpHeaders({
                'Authorization': `bearer ${token}`,
              })
            });
            return next.handle(req);
          })
        )
      }
    }
    

    请注意:我还没有测试过这段代码,我不能 100% 确定 ReplaySubject 是否是正确的选择。但是使用HttpInterceptor 和共享服务作为您的令牌应该是可行的方法。

    您可能还需要在 AuthInterceptor 中添加一些额外的逻辑,以不拦截登录请求和应用程序中不需要令牌的其他请求。

    有关如何提供和使用拦截器的说明,请参阅Angular Http Client Guide。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-10-19
      • 2017-07-04
      • 1970-01-01
      • 1970-01-01
      • 2019-05-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多