如何处理axios httpservice可观察到的响应



我觉得我疯了,因为我对节点和类型脚本还很陌生。。。我只想以同步的方式检索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
}
}

编辑:我在这里写完整的代码,因为它可能对其他学习该框架的人有用。我使用了周的回应,但里奇白也帮助我理解了背后的理论。当然,如果情况还能好转,就要改进/纠正。

  1. 我添加了一个类型来更好地控制对象
  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]}))),
    );
    }
    

如果您需要从Nest服务中执行此操作,并将结果返回给客户端,您可以简单地返回可观察到的结果,Nest将从那里为您处理订阅。如果需要进行任何额外的数据处理,可以在Observable.pipe()运算符之后使用map运算符。这方面的一个例子可能是从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;
})
);
}
}

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

编辑:

免责声明:我对Nest的具体了解不多,所以这个答案是从纯粹的JS角度来看的,不同的库有不同的内置能力。下面是对javascript中处理异步请求和可观察对象的不同方法的解释。我还强烈建议阅读异步javascript、可观察性和承诺,因为这将使您在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);
}

原始答案

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

// 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);

在这些选项中,选项3允许您使用异步和等待,这不是同步的,但允许您将异步方法中的其余代码视为异步方法,因此这可能最接近您想要的。我个人认为选项2是你最好的选择,因为你保留了可观察性的所有功能,包括所有可用的运算符。采用javascript中的异步代码,这是解决许多问题的最佳方案,而且往往是唯一的解决方案。

如果你比Observables:更熟悉promise和async/await,你也可以将HttpService(以及Axios(与Promises一起使用

const resp = await this.httpService.get(this.DATA_URL).toPromise(); // Here you get the AxiosResponse object.
const body = resp.data; // Here you get the response body, which is automatically parsed in the .data property of the AxiosResponse.

甚至:

const body = (await this.httpService.get(this.DATA_URL).toPromise()).data;

我使用等待,但您可以使用经典的promise语法:

this.httpService.get(this.DATA_URL).toPromise()
.then(resp => {
console.log(resp.data);
})
.catch(err => {
// Handle Error Here
console.error(err);
})

可以使用以下代码:

execute = async (): Promise<BondAssetType[]> => {

var response : Observable<BondAssetType[]> = this._assetBondTypeService.findAll().pipe(map(x => x.data));
var result:BondAssetType[] = await firstValueFrom(response);
return result;
}

最新更新