【问题标题】:Angular 4 - How can get value synchronously from an http request in another http request?Angular 4 - 如何从另一个http请求中的http请求同步获取价值?
【发布时间】:2018-04-17 05:51:33
【问题描述】:

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

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

此函数需要访问令牌才能调用 API。并且访问令牌可以通过auth.service中的getAccessToken()函数获取。

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

请注意,getCustomer() 必须是 Observable,以便我可以映射来自响应的数据并绑定到 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;
    }
}

customer-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.

【问题讨论】:

  • 我认为更好的设计模式是设置一个 HTTP 拦截器,该拦截器在任何 HTTP 调用上设置令牌(如果客户端不存在,则创建一个新的 HTTP cal 以获取令牌) .
  • 非常感谢,@AJT_82。我正在使用 flatMap,它现在可以工作了。

标签: angular angular-http-interceptors


【解决方案1】:

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

【讨论】:

    【解决方案2】:

    在我的脑海中,在您的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

    【讨论】:

    • 这对我不起作用。我收到错误A function whose declared type is neither 'void' nor 'any' must return a value.
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多