Angular 4 - 如何在另一个 http 请求中从一个 http 请求同步获取值?

Angular 4 - How can get value synchronously from an http request in another http request?

我正在为我的客户端应用程序使用 Angular 4。

customer.service 中的 getCustomer() 函数调用 API 来获取数据。这个函数是可观察的。

此函数需要访问令牌才能调用 API。并且可以从 auth.service.

中的 getAccessToken() 函数获取访问令牌

但是 getAccessToen() 是异步的。我们如何从异步函数中获取值?

请注意,getCustomer() 必须是可观察的,这样我才能从响应中映射数据并绑定到 customer.component 的成员。

auth.service.ts

import { Injectable } from '@angular/core';
import { Http, Headers } from '@angular/http';
import { Observable } from 'rxjs/Observable';

@Injectable()
export class AuthService {
    private tokenEndpoint = "http://localhost:9000/connect/token";
    private clientId = "testclientid";
    private clientSecret = "testsecret";

    constructor(private http: Http) { }

    getAccessToken() : Observable<any> {
        let credential = "Basic " + btoa(`${this.clientId}:${this.clientSecret}`);
        let body = "grant_type=client_credentials&scope=testscope";
        let headers = new Headers();
        headers.set("Content-Type", "application/x-www-form-urlencoded");
        headers.set("Authorization", credential);   

        return this.http.post(this.tokenEndpoint, body, { headers: headers })
            .map(result => {
                let data = result.json();
                return data.access_token || "";
            });                     
    }
}

customer.service.ts

import { Injectable } from '@angular/core';
import { Http, Headers } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';

import { Customer } from './customer';
import { Address } from './customer';
import { ResourceData } from './customer';
import { ResourceAttributes } from './customer';
import { CustomerResource } from './customer';
import { ResourceCollection } from './customer';
import { AuthService } from '../auth/auth.service';

@Injectable()
export class CustomerService {
    private customersUrl = "http://localhost:60001/api/v1/customers";

    constructor(private http: Http, private authService: AuthService) { }
    
    getCustomer(id: string): Observable<CustomerResource> {
  let accessToken = this.authService.getAccessToken().subcribe(
   // how to get accessToken from authService because subcribe is async?
  ); 
  
  let headers = addAccessTokenToHeader(accessToken);
 
        let url = `${this.customersUrl}/${id}`;
        return this.http.get(url, { headers: headers })
            .map(result => {                
                return result.json() as CustomerResource;
            })
            .catch((error) => {
                console.log(error);
                return Observable.throw(error);
            });
    }    

 private addAccessTokenToHeader(accessToken: string): Headers {
        let headers = new Headers();
        headers.set("Authorization", `Bearer ${accessToken}`);

        return headers;
    }
}

客户-detail.component.ts

showCustomer(id: string) {
    this.modalTitle = "Update PL customer";
    this.buttonSaveTitle = "Update";
    this.customerService.getCustomer(id)
        .subscribe(customer => {
            this.mapFromResource(customer.data);
            this.customerModal.show();
        });
}

private mapFromResource(data: ResourceData) {
    this.customerId = data.id;
    this.reference = data.attributes.reference;
    this.lastName = data.attributes.lastName;
    this.middleName = data.attributes.middleName;
    this.firstName = data.attributes.firstName;
}

// this.customerId, this.reference are the members of customer.component. They are binding on UI.

我没想到,在您的 customer.service.ts 中,您可以使用如下方式链接方法调用:

getCustomer(id: string): Observable<CustomerResource> {
  this.authService.getAccessToken()
    .map((accessToken) => { 
      let headers = addAccessTokenToHeader(accessToken);

      let url = `${this.customersUrl}/${id}`;
      return this.http.get(url, { headers: headers })
        // rest of the code
      }); 

如果不起作用,请尝试将 .map 替换为 .switchMap

我正在使用 flatMap,现在可以使用了。非常感谢您的建议@AJT_82