简体   繁体   English

Angular5如何使用Http Observable

[英]Angular5 How to use Http Observable

I have a problem with HTTP requests on Angular5. 我在Angular5上遇到HTTP请求问题。 I have two components (" LoginComponent ", " WellcomeComponent ") and one service (" AuthService "). 我有两个组件(“ LoginComponent ”,“ WellcomeComponent ”)和一个服务(“ AuthService ”)。

I am using auth servise to handle HTTP requests , and also this service is a bridge between two components. 我正在使用auth servise处理HTTP请求,并且此服务也是两个组件之间的桥梁。

I can do get and post requests from service , but can't use results properly, because of Observable things. 由于可以观察到的事情,我可以从service获取和发布请求,但不能正确使用结果。 I am not an experienced Angular developer so can't find a solution. 我不是经验丰富的Angular开发人员,所以找不到解决方案。

So now , I am explaining step by step. 所以现在,我正在逐步解释。 I will write all my code here, and all steps are signed by ..Step_ text in code, so you can follow all steps by this sign. 我将在此处编写所有代码,所有步骤均由代码中的..Step_文本签名,因此您可以按照此符号执行所有步骤。


LoginComponent LoginComponent

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");
    }

}

AuthService 验证服务

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;
    }

}

WellcomeComponent 惠康组件

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");
    }

}

If you look codes, there are a lot of console.log("Step.. , I am explaining what I want to do by using them. 如果您看代码,会有很多console.log(“ Step .. ,我正在解释我想通过使用它们来做什么。

In a short way, I can say I want to see them at this order in console screen : 简而言之,我可以说我想按以下顺序在控制台屏幕中看到它们:

  1. LoginStep_1 - Hello : This step will work by clicking a submit button on a form LoginStep_1-您好: 通过单击表单上的提交按钮,此步骤将起作用
  2. getToken_Step1 - Hello : Go to auth service getToken_Step1-您好: 转到身份验证服务
  3. getToken_Step2 - Token : Get token from an API and write it localStorage getToken_Step2-令牌: 从API获取令牌并将其写入localStorage
  4. getToken_Step3 - Bye getToken_Step3-再见
  5. LoginStep_2 - Token Verified : then come back and verify this token. LoginStep_2-令牌已验证: 然后返回并验证此令牌。
  6. setUserData_Step1 - Hello setUserData_Step1-您好
  7. setUserData_Step2 - User Info : Get user info from an API and write it localStorage setUserData_Step2-用户信息: 从API获取用户信息并将其写入localStorage
  8. setUserData_Step3 - Bye setUserData_Step3-再见
  9. LoginStep_3 - SetUserData Finished : I got token, verified it , got user info and wrote it. LoginStep_3 -SetUserData完成: 我得到了令牌,对其进行了验证,获得了用户信息并进行了编写。 So I can go navigate now. 所以我现在可以导航。
  10. Wellcome_Step1 - Hello : Navigated from Login Wellcome_Step1-您好: 从登录导航
  11. getUserData_Step1 - Hello : get all info that written by LoginComponent getUserData_Step1-您好: 获取LoginComponent编写的所有信息
  12. Wellcome_Step2 - Show User Info : Do what You want with user info Wellcome_Step2-显示用户信息: 使用用户信息执行所需操作

These steps are what I want to see on console log screen but, I can't see them with right order. 这些是我想在控制台日志屏幕上看到的步骤,但是我无法以正确的顺序看到它们。 My console output is very different from my expect. 我的控制台输出与我的预期有很大不同。 Because I don't know how to use angular 5 observable , so can't handle returned value from API. 因为我不知道如何使用angular 5 observable,所以无法处理API返回的值。

My console output something like that : 我的控制台输出类似这样的内容:

  1. LoginStep_1- Hello LoginStep_1-您好
  2. LoginStep_3 - SetUserData Finished LoginStep_3-SetUserData完成
  3. getToken_Step1 - Hello getToken_Step1-您好
  4. getToken_Step2 - Token getToken_Step2-令牌

... Here, why this order ? ...在这里,为什么要这个命令? How can I correct it ? 我该如何纠正?


So now , How can I do this ? 所以现在,我该怎么做? I want to take token and user info by LoginComponent and use them from WellCome component. 我想通过LoginComponent获取令牌和用户信息,并从WellCome组件中使用它们。

As I said, I am not an experienced coder, so maybe solution is very simple but couldn't find. 就像我说的,我不是一个有经验的编码员,所以也许解决方案很简单但是找不到。

Thank you for your helps. 谢谢您的帮助。

Because your requests to backend is asynchronous, it will take time to execute. 由于您对后端的请求是异步的,因此需要花费一些时间来执行。 Therefore, Angular will move on to other tasks: console.log('LoginStep_2 - Token Verified'); 因此,Angular将继续执行其他任务: console.log('LoginStep_2 - Token Verified'); and console.log('LoginStep_3 - SetUserData Finished'); console.log('LoginStep_3 - SetUserData Finished'); before the getToken() and setUserData() finished. 在之前getToken()setUserData()完成。

You can move subscribe to component 您可以移动订阅组件

In your AuthService 在您的AuthService中

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

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

In your component 在你的组件中

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

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

Basically, you should implement your function call to return either promise or observable (aka async). 基本上,您应该实现函数调用以返回promiseobservable (又称异步)。 The AuthService is something like this (adapted from your question): 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; }
}

You also need to setup a AuthGuard for your routing to track whether user is logged in or not. 您还需要为路由设置AuthGuard ,以跟踪用户是否登录。

Here is a working example stackblitz . 这是一个工作示例stackblitz Open console to track status 打开控制台以跟踪状态

Furthermore, you can always cache your user login status in browser localStorage to get better user experience. 此外,您始终可以将用户登录状态缓存在浏览器localStorage以获得更好的用户体验。 Again, this is adapted from your code. 同样,这是根据您的代码改编的。 There are many things can be improved from your code. 您的代码有很多可以改进的地方。 Let me know if you have further questions. 如果您还有其他问题,请告诉我。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM