如何处理 axios httpservice 可观察响应?
Posted
技术标签:
【中文标题】如何处理 axios httpservice 可观察响应?【英文标题】:How to process axios httpservice observable response? 【发布时间】:2020-07-09 12:35:20 【问题描述】:我觉得我快疯了,因为我对 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
编辑: 我在这里写了完整的代码,因为它可能对其他学习框架的人有用。我使用了周杰伦的回答,但richbai 对理解背后的理论也有很大帮助。如果它仍然可以变得更好,当然会改进/纠正。
-
我添加了一个类型来更好地控制而不是 Object
我需要将响应中的日期字段从“yyyy-mm-ddThh24:mi:ss”更改为“yyyy-mm-dd”
我还需要根据值过滤响应
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]))),
);
【问题讨论】:
你试过这个吗? ***.com/questions/34190375/… 例如,您可以将 rxjs Observable 转换为 Promise (.toPromise()
),然后只需 await
即可。
【参考方案1】:
如果您需要从 Nest 服务执行此操作,并将结果返回给客户端,您可以简单地返回 observable,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 将调用该服务,订阅 observable,并在后台返回数据。不需要额外的工作。如果您正在寻找有关 Observables 的更多信息,并且可用的操作 learnrxjs.io 是一个很好的来源。
【讨论】:
我添加了这个似乎是最佳选择的代码,您能否告诉我如何从 axiosResponse.data(这是一个数组)开始,我可以对数组元素进行进一步的拟合? 在我看来,关于 Observables 的伟大之处在于,几乎每个运算符都可以在同一个.pipe()
表达式中被链接起来,因此您可以在同一个管道中拥有多个运算符以使事情变得容易一起工作。例如,您可以拥有.pipe(tap(), map(), concatMap(), retryWhen(), catchError())
,它是一个有效的管道(只要这些函数中的每一个都完成了它应该做的事情)。在您的情况下,map((resp => resp.data), map(arrayData => arrayData.map(data => someFunciton))
其中arrayData
是来自 axios 的数据,arrayData.map
是 Array.prototype.map
函数【参考方案2】:
如果您对 Promises 和 async/await 比 Observables 更熟悉的话,您也可以将 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;
我正在使用 await,但您可以使用经典的 promise 语法:
this.httpService.get(this.DATA_URL).toPromise()
.then(resp =>
console.log(resp.data);
)
.catch(err =>
// Handle Error Here
console.error(err);
)
【讨论】:
toPromise()
在最新的@nestjs/axios
使用的RXJS 8 中已被弃用。您会收到上述代码的弃用警告。【参考方案3】:
编辑:
免责声明:我对 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);
原答案
您不能以同步方式从可观察对象中检索值。您必须订阅它并在返回值后执行某些操作,或者将其转换为 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 允许您使用 async 和 await,这不是同步的,但允许您将 async 方法中的其余代码视为同步,因此这可能最接近您想要的。我个人认为选项 2 是您最好的选择,因为您保留了 observables 的所有功能,包括所有可用的运算符。在 javascript 中使用异步代码,它是解决许多问题的最佳方案。
【讨论】:
我很困惑...该代码位于后端 REST 控制器内部,并由外部 API 调用。我只想让我的服务器检索数据,过滤它并最终将其返回给客户端......方法2可能吗?只有一个似乎是 3,但无法理解为什么在诸如嵌套之类的服务器端框架中它们使它变得如此复杂:(以上是关于如何处理 axios httpservice 可观察响应?的主要内容,如果未能解决你的问题,请参考以下文章
vue 第一次axios请求得到一个数组,然后根据循环数组获得id进行第二次axios请求,请问如何处理速度最快?
在 NestJS 中缓存 axios httpService