【问题标题】:Angular5 How to use Http ObservableAngular5如何使用Http Observable
【发布时间】:2018-05-21 23:52:06
【问题描述】:

我在 Angular5 上遇到 HTTP 请求问题。 我有两个组件(“LoginComponent”、“WellcomeComponent”)和一个服务(“AuthService”)。

我使用 auth servise 来处理 HTTP 请求,而且这个服务是两个组件之间的桥梁。

我可以从 service 获取和发布请求,但由于 Observable 的原因,无法正确使用结果。我不是经验丰富的 Angular 开发人员,所以找不到解决方案。

所以现在,我正在一步一步地解释。我把我所有的代码都写在这里了,所有的步骤都用代码中的..Step_文字签名,所以你可以通过这个符号来执行所有的步骤。


登录组件

import { Component } from '@angular/core';
import { Router } from '@angular/router';
import { AuthService } from '../../auth.service';

@Component({
  selector: 'app-login',
  templateUrl: './login.component.html'
})
export class LoginComponent {

    loginUserData = {}

    constructor(
        private _auth: AuthService,
        public router:Router ){
            //SOMETHING
        }

    //CLICK FORM SUBMIT BUTTON
    public onSubmit(values:Object):void {

        //SET USER DATA WITH FORM VALUES
        console.log("LoginStep_1 - Hello")

        this._auth.getToken(this.loginUserData)
        // CHECK TOKEN

        // IF VERIFIED
            console.log('LoginStep_2 - Token Verified');

            this._auth.setUserData(this.loginUserData['username']);
            console.log('LoginStep_3 - SetUserData Finished');

            this.router.navigate(['/wellcome'])
            console.log("LoginStep_4 - Navigated");
    }

}

身份验证服务

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Router } from '@angular/router';

@Injectable()
export class AuthService {

    private _tokenUrl = "http://localhost:8000/api/auth/token/";
    private getUserInfoUrl = "http://127.0.0.1:8000/api/userInfo/?username="
    private userInfo : any;

    constructor(
        private http: HttpClient,
        private _router: Router
    ) { }

    getToken(user){
        console.log("getToken_Step1 - Hello");

        this.http.post<any>(this._tokenUrl, user)
        .subscribe(
            res => {

                //getToken_Step2 : SET TOKEN SOMEWHERE
                console.log("getToken_Step2 - Token : ", res.token);

            },
            err => console.log(err)
        );

        console.log("getToken_Step3 - Bye");
    }

    setUserData(userName){
        console.log("setUserData_Step1 - Hello");

        this.http.get<any>(this.getUserInfoUrl+userName)
        .subscribe(
            res=>{

                //setUserData_Step2 : SET USERINFO SOMEWHERE
                console.log("setUserData_Step2 - User Info : ", res);

            },
            err=>{
                console.log(err);
            }
        )

        console.log("setUserData_Step3 - Bye");
    }

    getUserData(){
        console.log("getUserData_Step1 - Hello");
        return this.userInfo;
    }

}

威康组件

import { Component, OnInit } from '@angular/core';
import { AuthService } from '../../../auth.service';

@Component({
  selector: 'app-wellcome',
  templateUrl: './wellcome.component.html',
  styleUrls: ['./wellcome.component.scss'],
})
export class WellcomeComponent implements OnInit {

    constructor(private _auth: AuthService){ }

    ngOnInit() {
        console.log("Wellcome_Step1 - Hello");
        let userInfo = this._auth.getUserData();
        console.log("Wellcome_Step2 - Show User Info");
    }

}

如果你看代码,有很多 console.log("Step..,我正在解释我想通过使用它们来做什么。

简而言之,我可以说我想在控制台屏幕中按此顺序查看它们:

  1. LoginStep_1 - 您好:此步骤将通过单击表单上的提交按钮来工作
  2. getToken_Step1 - 你好:转到身份验证服务
  3. getToken_Step2 - 令牌:从 API 获取令牌并将其写入 localStorage
  4. getToken_Step3 - 再见
  5. LoginStep_2 - 令牌验证:然后回来验证这个令牌。
  6. setUserData_Step1 - 你好
  7. setUserData_Step2 - 用户信息:从 API 获取用户信息并将其写入 localStorage
  8. setUserData_Step3 - 再见
  9. LoginStep_3 - SetUserData 完成:我得到了令牌,验证了它,得到了用户信息并写了它。所以我现在可以去导航了。
  10. Wellcome_Step1 - 你好:从登录导航
  11. getUserData_Step1 - 你好:获取所有由 LoginComponent 编写的信息
  12. Wellcome_Step2 - 显示用户信息:用用户信息做你想做的事

这些步骤是我想在控制台日志屏幕上看到的,但是我看不到它们的正确顺序。我的控制台输出与我的预期非常不同。因为我不知道如何使用 angular 5 observable ,所以无法处理来自 API 的返回值。

我的控制台输出类似的东西:

  1. Lo​​ginStep_1- 你好
  2. Lo​​ginStep_3 - SetUserData 完成
  3. getToken_Step1 - 你好
  4. getToken_Step2 - 令牌

... 在这里,为什么这个命令?我该如何纠正它?


那么现在,我该怎么做呢?我想通过 LoginComponent 获取令牌和用户信息,并从 WellCome 组件中使用它们。

正如我所说,我不是一个经验丰富的编码员,所以也许解决方案很简单但找不到。

感谢您的帮助。

【问题讨论】:

  • 因为日志记录本质上是异步,所以您的AuthService 应该考虑到这一点。具体来说,您的getUserData 应该返回一个Observable

标签: angular angular5 angular2-services angular-http angular2-observables


【解决方案1】:

由于您对后端的请求是异步的,因此执行需要一些时间。因此,Angular 将在 getToken()setUserData() 完成之前继续执行其他任务:console.log('LoginStep_2 - Token Verified');console.log('LoginStep_3 - SetUserData Finished');

你可以移动订阅组件

在您的 AuthService 中

    getToken(user){
        console.log("getToken_Step1 - Hello");

        return this.http.post<any>(this._tokenUrl, user)
        // subscribe moves to component
    }

在你的组件中

this._auth.getToken(this.loginUserData)
  .subscribe(
    res => {

      //getToken_Step2 : SET TOKEN SOMEWHERE
      console.log("getToken_Step2 - Token : ", res.token);
    },
    err => console.log(err)
  )

【讨论】:

  • 以上网络服务调用和订阅的细分也对我有用。
【解决方案2】:

基本上,您应该实现您的函数调用以返回promiseobservable(又名异步)。 AuthService 是这样的(改编自您的问题):

import {Injectable} from '@angular/core';
import {HttpClient, HttpHeaders} from '@angular/common/http';

import {Observable, of} from 'rxjs';

@Injectable()
export class AuthService {
  constructor(private http: HttpClient) {}

  // private _tokenUrl = "http://localhost:8000/api/auth/token/";

  // This is just a mock URL that returns a response (200 OK)
  private _tokenUrl =
      "https://bikewise.org:443/api/v2/incidents?page=1&proximity_square=100";
  // private getUserInfoUrl = "http://127.0.0.1:8000/api/userInfo/?username=";
  private userInfo: any;

  // can improve with getter/setter instead of exposing directly
  private isLoggedIn: boolean = false;

  isLoggedInObservable: Observable<boolean>;

  getToken(user): Promise<any> {
    console.log("getToken_Step1 - Hello");

    return new Promise(resolve => {

      // this.http.post<any>(this._tokenUrl, user)
      // fake request to make sure always get a response
      this.http.get<any>(this._tokenUrl)
          .subscribe(
              res => {

                // getToken_Step2 : SET TOKEN SOMEWHERE
                console.log("getToken_Step2 - Token : ", "token_1234");

                console.log("getToken_Step3 - Bye");
                // resolve(res.token);
                resolve("token1234");

              },
              err => {
                console.log(err);

                throw new Error('Unauthorized...');

              });
    })
  }

  setUserData(userName) {
    console.log("setUserData_Step1 - Hello");

    // If this is a real request, make sure to implement a promise/observable
    // return
    // this.http.get<any>(this.getUserInfoUrl + userName)

    // setUserData_Step2 : SET USERINFO SOMEWHERE
    console.log("setUserData_Step2 - User Info : ");

    console.log("setUserData_Step3 - Bye");
    this.isLoggedIn = true;
    this.isLoggedInObservable = of(true);
  }

  getUserData() {
    console.log("getUserData_Step1 - Hello");
    return this.userInfo;
  }

  logOut() {
    this.isLoggedInObservable = of(false);
    this.isLoggedIn = false;
  }

  isLogged(): boolean { return this.isLoggedIn; }
}

您还需要为您的路由设置AuthGuard 以跟踪用户是否登录。

这是一个工作示例stackblitz打开控制台以跟踪状态

此外,您可以随时在浏览器localStorage中缓存您的用户登录状态,以获得更好的用户体验。同样,这是根据您的代码改编的。您的代码有很多可以改进的地方。如果您还有其他问题,请告诉我。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-09-15
    • 1970-01-01
    • 2018-08-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多