【问题标题】:Multiple Observables sharing single Error rxjs angular多个 Observables 共享单个 Error rxjs angular
【发布时间】:2020-08-28 23:35:04
【问题描述】:

我正在尝试使用 Oauth2 身份验证来处理 API 请求。

我有一个authService 具有三个属性(accessTokenrefreshTokenrefreshTokenObservable - 稍后将描述)和apiGet() 方法,它使用 Authorization 标头创建 HTTP GET 请求,如下所示:

apiGet(cleanedPath:string) {
  return this.config.getConfig().pipe(mergeMap((config: Config) => {
    
    [...] // Cleans parameters and creates a final query string

    // Adding access token as header
    let headers: object = {headers: new HttpHeaders().set('Authorization', this.accessToken)}

    return this.http.get<any>(cleanedPath, headers).pipe(catchError(this.handleApiGetError.bind(this, cleanedPath)));
  }));
}

我希望handleApiGetError() 方法调用新的刷新令牌并尝试重复apiGet(),我尝试将多个apiGet() 调用连接到单个可观察对象,如下所示:

private handleApiGetError(cleanedPath:string, error: HttpErrorResponse) {
  if (!this.refreshTokenObservable) {
    // getAccessByRefreshToken() is simple HTTP post
    this.refreshTokenObservable = this.getAccessByRefreshToken();
  }
  return this.refreshTokenObservable.pipe(mergeMap(()=> {
    return this.apiGet(cleanedPath);
  }));
}

但是,这不起作用,因为它在每个失败的 apiGet() 中调用新令牌,导致 OAuth 服务返回多个 E401(令牌已被撤销)。

有没有办法将apiGet() Observers 绑定在一起,并且在错误的情况下只调用一次刷新令牌请求并重新调用失败的apiGet() 调用?

【问题讨论】:

    标签: angular rxjs observable


    【解决方案1】:

    考虑使用retryWhen 仅重试一次,最重要的是反转控制,这样您的ErrorHandler 就无需负责再次重试(通过调用其调用者)。
    使用retryWhen,你的HTTP请求只有在this.handleApiGetError()返回的Observable完成后才会重试,如下所示:

    apiGet(cleanedPath: string) {
      return this.config.getConfig().pipe(
        mergeMap((config: Config) => {
          return this.http.get<any>(cleanedPath, headers).pipe(
            retryWhen(x => this.handleApiGetError())
          );
        })
      );
    }
    
    private handleApiGetError(error: HttpErrorResponse) {
      return this.refreshTokenObservable;
    }
    

    话虽如此,handleApiGetError 可能是不必要的,因为您可以直接调用getAccessByRefreshToken,如下所示:

     apiGet(cleanedPath: string) {
       return this.config.getConfig().pipe(
         mergeMap((config: Config) => {
           return this.http.get<any>(cleanedPath, headers).pipe(
             retryWhen(this.getAccessByRefreshToken)
           );
         })
       );
     }
    

    【讨论】:

    • 我尝试使用您的方法。问题是它仍然为每个 apiGet() 调用使用单独的 POST 请求。
    猜你喜欢
    • 1970-01-01
    • 2020-02-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-04
    • 1970-01-01
    • 2017-03-20
    • 1970-01-01
    相关资源
    最近更新 更多