无法在函数内再次调用 api

Can't call api again inside function

我的请求有问题。
这个想法是,如果请求失败,因为令牌过期功能将发送登录请求(使用会话数据中的数据)并将再次发送原始请求和 return 值。
我认为对此可能有明显的解决方案,但我几乎没有用 js 编写代码。 知道如何解决吗?

代码在这里:

  apiCall(url, body, first = true) {

    const httpOptions = {
      headers: new HttpHeaders()
        .set('Authorization', `Bearer ${sessionStorage.getItem('jwt')} `),
    };
    this.deleteNullParams(body);
    return this.httpClient.post(this.API_URL + url, body, httpOptions).pipe(
      map(response => {
        if (response['result'] != 'success' && first) {
          console.log("Failed");
          this.loginWithSessionData();
          return this.apiCall(url, body, false);
        }
        else {
          return response;
        }
      })
    );
  }

getLocationDetails(body) {
    return this.apiCall('/api/locationList', body);
  }

  loginWithSessionData() {
    let password = sessionStorage.getItem('password');
    let username = sessionStorage.getItem('username');
    if (password && password != '' && username && username != '') {
      const json = {};
      json['username'] = username;
      json['password'] = password;
      this.userLogin(json).subscribe((res: any) => {
        if (res['body']['result'] !== 'failed') {
          sessionStorage.setItem('jwt', res.body['data'].token);
          localStorage.setItem('login_data', JSON.stringify(res.body['data']));
          return true;
        }
      }, (error) => { });
    }
    else {
      sessionStorage.clear();
    }
    return false;
  }

所以我想在获得有效令牌后再次 return apiCall,但由于某些原因,除登录之外的任何其他请求都不会在 apiCall 函数中发送。

编辑
更具体地说,调用函数时会发生什么:
尝试获取数据,
由于没有(或过期)令牌而失败,
发送登录请求,获取,
设置令牌就是这样,
直到下一个 refresh/change 页才会发送更多请求。

回答

好的,接受的答案是正确的,只需添加 returns:

  apiCall(url, body, first = true) {
    const httpOptions = {
      headers: new HttpHeaders()
        .set('Authorization', `Bearer ${sessionStorage.getItem('jwt')}`)
    };
    this.deleteNullParams(body);
  
    return this.httpClient.post(this.API_URL + url, body, httpOptions).pipe(
      switchMap((response: any) => {
        return iif(
          () => response['result'] != 'success' && first,
          this.loginWithSessionDataObs().pipe(switchMap(() => this.apiCall(url, body, false))),
          of(response)
        )
        
      })
    );
  }

从可观察对象中获取值是异步的,这意味着您不能期望在订阅回调之后写一些语句,然后在回调之后执行。他们会运行更早。

在您的情况下,您需要使用多个 RxJS 函数(ofiif)和运算符(switchMap)以使其相互依赖。

apiCall(url, body, first = true) {
  const httpOptions = {
    headers: new HttpHeaders()
      .set('Authorization', `Bearer ${sessionStorage.getItem('jwt')}`)
  };
  this.deleteNullParams(body);

  this.httpClient.post(this.API_URL + url, body, httpOptions);.pipe(
    switchMap((response: any) => {
      iif(
        () => response['result'] != 'success' && first,
        this.loginWithSessionData().pipe(switchMap(() => this.apiCall(url, body, false))),
        of(response)
      )
    })
  );
}

loginWithSessionData(): Observable<any> {     // <-- return observable here
  let username = sessionStorage.getItem('username');
  let password = sessionStorage.getItem('password');

  const storeData = (data: any) => {
    sessionStorage.setItem('jwt', data.body['data'].token);
    localStorage.setItem('login_data', JSON.stringify(data.body['data']));
  }

  return iif(
    () => (password && password != '' && username && username != ''),
    this.userLogin({ username: username, password: password }).pipe(
      map((data: any) => {
        storeData(data);
        return true;
      })
    ),
    of(false).pipe(tap(() => sessionStorage.clear()))
  );
}

然而,尽管它可能有效,但我想说可能有更好的方法来重新触发 HTTP 请求而不是递归调用。例如,您可以在最初不触发 HTTP 请求的情况下检查 token expiration