Angular 2 的新 HttpClient 中的 Observable Chaining

Observable Chaining in Angular 2's new HttpClient

我有一个简单而常见的场景,但我无法理解使用新 HttpClient 执行此操作的正确方法。我来自 Angular 1 和 chainable then() 承诺,但不确定如何使用 Observables 实现这一点。 (如果更新英雄之旅教程以反映向 HttpClient 的转变,那就太好了)。

我有一个主app.component.ts。该组件将在 authentication.service.ts.

中调用 AuthenticationService.login()

AuthenticationService 有两个目的:

  1. 它协调有关身份验证的所有 client/server 通信。
  2. 它存储可以在任何 and/or 所有组件之间共享的身份验证信息。

理想情况下代码非常简单(注意:这只是人为的伪代码)

app.component.ts:

export class AppComponent {
  loggedIn: boolean = false;

  constructor(private authenticationService: AuthenticationService) {
  }

  login() {
    // I want to do this but don't know how
    this.authenticationService.login(this.userLoginForm.email, this.userLoginForm.password).then(function(loggedIn) {
      this.loggedIn = loggedIn;
    }
  }
}

authentication.service.ts:

@Injectable()
export class AuthenticationService {
  user: User;

  constructor(private http: HttpClient) {
    // do stuff
  }

  // Recommendations I'm reading tend to prefer using Observables
  // instead of Promises. But I like the `then()` chaining that
  // I'm not sure how to do with Observables

  // Return what here? Observable<boolean> ?
  login(email, password): Observable<boolean> {
      const url = `http://127.0.0.1/token/auth`;

      // post() returns a LoginResponse that we subscribe to and handle here,
      // but I want to return a promise-like object that will resolve to
      // a boolean
      return this.http.post<LoginResponse>(url, {email: email, password: password})
          .subscribe(
            loginResponse => {
              if (loginResponse.error) {
                // set user to a new unauthenticated user
                this.user = new User();
              } else {
                this.user = JSON.parse(loginResponse.data.user) as User;
              }

              localStorage.setItem('currentUser', JSON.stringify(this.user));

              // returning a boolean here to the caller would be nice
              return this.user.id != null;
            }
          }
        );  
  );

}

我在这里错过了什么?这不是微不足道的吗?

可以说,这里不需要 return 布尔值。 app.component.ts 只读AuthenticationService.user 就可以知道用户是否登录了?是这样吗?

更一般地说,服务肯定必须有一种方法来处理来自服务器的数据 return,然后解决调用组件正在等待的承诺。如何做到这一点?

您可以使用 toPromise() 函数将 Observable 转换为 Promise。现在你的 login 将 return Promise,而不是 Observable,你可以通过 thens.

链接它
login(email, password) : Promise {
      const url = `http://127.0.0.1/token/auth`;

      return this.http.post<LoginResponse>(url, {email: email, password: password})
          .toPromise().then(loginResponse => {
              this.user = loginResponse.error ? this.user = new User() :
                                                JSON.parse(loginResponse.data.user) as User;

              localStorage.setItem('currentUser', JSON.stringify(this.user));

              return this.user.id !== null;
          });  
}

您可以使用 Obervable.map 将事物转换为您的服务应该 return 的东西(您需要一个可观察的布尔值)。在任何地方都使用 observable,因此在您的组件中将 .then 更改为 .subscribe。

// Your service:

@Injectable()
export class AuthenticationService {

    user: User;

    constructor(private http: HttpClient) {
    // do stuff
    }

    login(email, password): Observable<boolean> {

        const url = `http://127.0.0.1/token/auth`;

        return this.http.post<LoginResponse>(url, { email: email, password: password })
            .map(loginResponse => {
                this.user = loginResponse.error ? new User() : (JSON.parse(loginResponse.data.user) as User);
                localStorage.setItem('currentUser', JSON.stringify(this.user));
                return this.user.id != null;
            }
    }        
}

// Your component
export class AppComponent {

    loggedIn: boolean = false;

    constructor(private authenticationService: AuthenticationService) { }

    login() {
        this.authenticationService.login(this.userLoginForm.email, this.userLoginForm.password).subscribe(loggedIn =>  this.loggedIn = loggedIn);
    }
}