如何处理 axios httpservice observable 响应?

Pha*_*ate 3 typescript axios nestjs

我想我快疯了,因为我对 node 和 typescript 还很陌生……我只是想以同步的方式检索 http get 请求的结果。

鉴于:

import { Injectable, HttpService } from '@nestjs/common';
import {} from '@nestjs/core';

@Injectable()
export class AppService {
  private readonly DATA_URL:string = "https://remote/data.json";
  constructor(private httpService:HttpService){}
  getSomething(): Array<Object> {
   let resp = this.httpService.get(this.DATA_URL); //what do I do now?? It's an observable
  }
}
Run Code Online (Sandbox Code Playgroud)

编辑:我在这里写了完整的代码,因为它可能对其他人学习框架有用。我用了Jay的回答,但是richbai对我理解背后的理论也有很大帮助。当然,如果它仍然可以变得更好,请改进/纠正。

  1. 我添加了一个类型来更好地控制而不是 Object
  2. 我需要将日期字段从“yyyy-mm-ddThh24:mi:ss”响应更改为“yyyy-mm-dd”
  3. 我还需要根据值过滤响应

     getSomething(aFilterValue:number): Observable<RespDTO[]> {
        return this.httpService.get(this.DATA_URL).pipe(
        map((axiosResponse : AxiosResponse) => (axiosResponse.data as 
       RespDTO[])
    .filter((el:RespDTO) => el.aCode===aFilterValue)
    .map((el:RespDTO) => ({...el,aDateField:el.aDateField.split('T')[0]}))),
    );
    }
    
    Run Code Online (Sandbox Code Playgroud)

Jay*_*iel 6

如果您需要从 Nest 服务执行此操作,并将结果返回给客户端,您只需返回 observable,Nest 将从那里为您处理订阅。如果你不需要做任何额外的数据处理,你可以使用map后运营商.pipe()的运营商Observable。一个例子可能是从 axios 响应中获取数据,而不是整个响应(这会遇到问题,JSON.stringify()因为它本身有循环引用)。

下面是这样的一个例子

import { Injectable, HttpService } from '@nesjts/common';
import { AxiosResponse } from 'axios';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';

@Injectable()
export class HttpConsumingService {
  private readonly DATA_URL = 'http://remote/data.json';
  constructor(private readonly http: HttpService) {}

  callHttp(): Observable<Array<Object>> {
    return this.http.get(this.DATA_URL).pipe(
      map((axiosResponse: AxiosResponse) => {
        return axiosResponse.data;
      })
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

从这里开始,如果您有一个调用 的控制器this.httpConsumingService.callHttp(),Nest 将调用该服务,订阅 observable,并在后台从它返回数据。不需要额外的工作。如果您正在寻找有关 Observables 和可用操作的更多信息,learnrxjs.io是一个非常好的来源。


ric*_*i90 5

编辑:

免责声明:我对 Nest 不太了解,所以这个答案是从纯粹的 JS 角度来看的,不同的库有不同的内置功能。下面是对 JavaScript 中处理异步请求和可观察量的不同方法的解释。我还强烈建议您阅读异步 javascript、observables 和 Promise,因为它会让您在 javascript 中度过更加愉快的时光。

JavaScript 中的 Web 请求是异步发生的,这意味着它们或多或少与其余同步代码并行执行。您可以将其想象为一个单独的线程,尽管事实并非如此。这意味着依赖于此 Web 请求的值的代码必须停止,直到请求完成。从我下面的原始帖子来看,您的情况中最简单的选项可能是选项 3。使用它的代码可能看起来有点像这样:

/**
 * A method in your rest controller that relies on the getSomething() 
 * method as implemented in option 2 below
 */
async showRemoteData() {  
  const remoteData = await appService.getSomething();
  // replace console.log with whatever method you use to return data to the client
  console.log(remoteData);
}
Run Code Online (Sandbox Code Playgroud)

原答案

您无法以同步方式从可观察对象中检索值。您必须订阅它并在返回值后执行某些操作,或者将其转换为承诺并返回承诺。您的选择是:

// option 1 change getSomething to doSomething, and do everything in that method

doSomething(): Array<Object> {
  let resp = this.httpService.get(this.DATA_URL);
  resp.subscribe((value) => { // do something })
}

// option 2 return the observable and subscribe to it outside of that method
getSomething(): Array<Object> {
  return this.httpService.get(this.DATA_URL);
}
// outside of the AppService you can use it like this
appService.getSomething().subscribe((value) => {// do something})

// option 3 convert the observable to a promise and return it
getSomething(): Array<Object> {
  return this.httpService.get(this.DATA_URL).toPromise();
}
// outside of the AppService you can use it like this
let value = await appService.getSomething();
console.log(value);
Run Code Online (Sandbox Code Playgroud)

在这些选项中,选项 3 允许您使用异步和等待,它不是同步的,但允许您将异步方法中的其余代码视为同步,因此这可能最接近您想要的。我个人认为选项 2 是你最好的选择,因为你保留了 observable 的所有功能,包括可供你使用的所有操作符。在 JavaScript 中拥抱异步代码,它是解决许多问题的最佳且通常是唯一的解决方案。