角度:等待一个可观察到的返回以发起另一个

时间:2018-11-27 10:31:14

标签: angular typescript http asynchronous

我的业务场景是这样的: 首先,我向WebAPI中的token()端点发出HTTP请求以获取身份验证令牌(这发生在app.component.ts中)。然后,我有一个令牌拦截器模块,将令牌附加到后续请求的HTTP标头中。

然后,我在WebAPI中有一个getLanguages()端点,并且在我的标头组件header.component.ts中调用了该端点。因此,此调用将通过HTTP拦截器进行尝试,并尝试将生成的令牌附加到请求标头中,但是由于token()端点尚未返回,因此getLanguages()端点未通过身份验证而失败。

我显然在这里丢失了一些东西。我已经读过ReplaySubject的内容,但不确定如何将所有内容放在一起。

这是我当前的代码。

app.component.html:

<app-header>
</app-header>
<router-outlet></router-outlet>
<app-footer>
</app-footer>

auth.service.ts:

 authenticateClient(){

let body = new HttpParams()
  .set('client_id', AppConst.GLOBAL.auth.client_id)
  .set('grant_type', AppConst.GLOBAL.auth.grant_type)
  .set('scope', AppConst.GLOBAL.auth.scope);

const httpOptions = {
  headers: new HttpHeaders({
    'Content-Type': 'application/x-www-form-urlencoded'
  })
};

let authGatewayUrl: string = AppConst.GLOBAL.authApiUrl + window.location.search;

return this.http.post(authGatewayUrl, body.toString(), httpOptions)
          .pipe(map((res: any) => this.token = res), catchError(this.handleErrorObservable));
      }

  getToken(): Token {
    return this.token;
  }

app.component.ts:

token: Token;

 ngOnInit() {
// get the authentication token and store it for usage in subsequent API calls.
this.authService.authenticateClient().subscribe(
  obj => this.token = obj as Token,
  err => alert(err)
  );
  }

app.service.ts:

  getLanguages() {
 return this.http.get(this.localeApiUrl)
  .pipe(map((res: any) => this.languages = res), catchError(this.handleErrorObservable));
  }

header.component.ts:

   constructor(private appService: AppService) {
    this.appService.getLanguages().subscribe(obj => this.languages = obj);

  };

http-interceptor.ts:

intercept(req: HttpRequest<any>, next: HttpHandler) {
// exclude the token API endpoint from the interception
const loginUrl: string = AppConst.GLOBAL.authApiUrl;

if (req.url.search(loginUrl) === -1) {
  // Get the auth token from the service.
  const authToken = this.auth.getToken();

  //// Clone the request and set the new header in one step.
  req = req.clone({ setHeaders: { Authorization: authToken.access_token } });
}

//// send cloned request with header to the next handler.
return next.handle(req);
 }

2 个答案:

答案 0 :(得分:2)

您可以将令牌信息保存在AuthService内部的BehaviorSubject中。

然后在.next(token)成功时触发authenticateClient()

header.component中,您可以这样做。

  readonly languages$ = this.authService.token$.pipe(
    first(!!token), // or filter, depends on your application logic
    switchMap(() => this.appService.getLanguages(),
  );

  this.languages$.subscribe(obj => this.languages = obj);

在上面的代码中,您将从authService创建一个新的Observable,当有人在令牌next上触发BehaviorSubject时,此Observable会检查是否已定义令牌,如果已定义,则可以调用您的内部API。

这是一种方法,但我认为还有其他解决方案。

答案 1 :(得分:-4)

您也可以使用Promise。

var promise = new Promise((resolve, reject) => {
setTimeout(() => {
  console.log("Async Work Complete");
  if (error) {
    reject();
  } else {
    resolve();
  }
}, 1000);

});