如何处理angular 4 HttpClient在服务中的响应并通知组件

How to process angular 4 HttpClient's response in the service and notify component

我想知道,如何在响应完成后使用新的 HttpClient(来自@angular/common/http 的angular 4.3+)轻松通知组件有关 http 响应(成功或错误)由服务处理(保存令牌)。

早些时候,我使用了这段代码(使用@angular/http):

login(username: string, password: string): Observable<any> {    
  let headers = new Headers({ 'Content-Type': 'application/x-www-form-urlencoded' });
  let options = new RequestOptions({ headers: headers });

  let url = this.apiAddr + '/login';
  var body = 'username=' + username + '&password=' + password;

  return this.http.post(url, body, options).map((res) => {
    let body = res.json();

    this.jwtoken = body.token;
    this.username = username;
    this.saveToken();                           
    return "Login successful!";
  })
  .catch(this.handleError);
 }

通过使用新模块,我不确定如何 return Observable 并同时从服务访问它。这是我目前拥有的 (auth.service.ts):

login(username: string, password: string) {
  const headers = new HttpHeaders().set('Content-Type', 'application/x-www-form-urlencoded');
  const url = apiAddr + '/login';
  const body = 'username=' + username + '&password=' + password;
  const options = {
    headers: headers,
  };


  this.http.post<LoginResponse>(url, body, options).subscribe(
    data => {
      this.jwtoken = data.token;
      this.username = username;
      this.lastTokenRefreshAt = new Date();
      this.saveUserToken();
    }, err => {
      console.log('Error occured');
      console.log(err);
    });
}

之后,我想通知 LoginComponent,在那里我可以导航到不同的页面。

当组件像这样调用它时,使用 observable 的 do 运算符访问来自服务的响应:

import 'rxjs/add/operator/do';

login(username: string, password: string) {
  const headers = new HttpHeaders().set('Content-Type', 'application/x-www-form-urlencoded');
  const url = apiAddr + '/login';
  const body = 'username=' + username + '&password=' + password;
  const options = {
    headers: headers,
  };

  return this.http.post<LoginResponse>(url, body, options).do(
    data => {
      this.jwtoken = data.token;
      this.username = username;
      this.lastTokenRefreshAt = new Date();
      this.saveUserToken();
  });
}

您可以在调用登录的组件中捕获错误。

更新到 angular6 并使用新版本的 RxJs 后,我不得不更改 do 方法,因为它是 renamed/deprecated。为了获得与 Sonicd300 的答案类似的结果,我必须使用带管道的 tap 方法:

import { tap } from 'rxjs/operators';

login(username: string, password: string) {
  const headers = new HttpHeaders().set('Content-Type', 'application/x-www-form-urlencoded');
  const url = this.apiAddr + '/login';
  const body = 'username=' + username + '&password=' + password;
  const options = {
    headers: headers,
  };
  return this.http.post<LoginResponse>(url, body, options).pipe(
    tap(
      data => {
        this.jwtoken = data.token;
        this.username = username;
        this.lastTokenRefreshAt = new Date();
        this.saveUserToken();
        return 'Login successful';
      })
  );
}