node.js - Node.js/NestJS:强制执行 HTTP 调用(使其成为更热的 Observable)
问题描述
我正在为一些最终用户开发一个库,通过 HttpService 调用 API ,最终用户将使用或不使用其结果。
end-user consumer <==> my library <=(HTTP)=> remote API
现在 HttpService 使用冷 Observables,这意味着只有当我们订阅生成的 Observable 时它才会触发 HTTP 调用。如果我将此 Observable 返回给我的最终用户,并且他们不订阅它,因为在他们的特定用例中他们不需要结果,则永远不会调用 API。
出于这个原因,我倾向于在将 Observable 返回给最终用户之前先订阅它,但我不确定它是一个优雅或安全的解决方案,因此这篇文章。我的代码如下所示(为帖子简化,并使用来自@nestjs/common 的 HttpService):
ServiceToAccessAPIData.ts
export class ServiceToAccessAPIData {
...
callToEndPoint(): Observable<any> {
const obs = httpService.get(someUrl)
.pipe(
shareReplay(1) // see A
);
obs.subscribe(()=>{},()=>{}); // see B
return obs;
}
...
}
和:
- A : 因为我想避免每个订阅都发出一个 HTTP 调用,所以我需要在订阅者之间共享调用结果;并且因为我现在(在 B 中)订阅并且最终用户可能会稍后订阅(即使在 API 发送结果之后)并且他们显然不应该错过结果,所以我使用了 shareReplay(1) 运算符,它存储了最后一个结果,并将其发送给任何新订阅者。
- B : 我现在订阅强制 HTTP 调用立即进行。我们提供成功但尤其是错误处理方法,因为未处理的异常会炸毁 Node.js 服务器)。
现在,对于这样一个微不足道的用例来说,这似乎有点复杂:“为最终用户提供一种安全的方式来拨打电话,无论他们是否使用结果”。
有没有更好、更简单、更优雅的方式来做到这一点?
此外,在性能方面,这种技术会有什么结果吗?
HttpService Observers 只发出一次然后完成,因此订阅将自动“取消订阅”。但我想知道 shareReplay 观察到的底层 Observer 会变成什么。我想当我返回的 Observable 不再引用它时,它将被垃圾收集,但我想知道。
使用 Promises(由 MoazzamArif 建议)
上面的问题仍然存在(特别是如果需要坚持使用 Observables),但最初问题的解决方案可能是使用.toPromise()作为返回给最终用户的值。
return obs.toPromise();
.toPromise() 订阅Observable(让它立即执行 HTTP 调用)并将其包装在 Promise 中,一旦 Observable 完成(在 HttpService 的情况下,只要API 返回了一个结果)。
=> 这实际上满足了“为最终用户拨打电话提供安全的方式,无论他们是否使用结果”的需求。
现在让我们进一步挖掘。我想这是一个需要考虑的异国情调和奇怪的场景,但我们如何处理这种情况:
- HTTP 调用期间发生错误
- 最终用户链 .then() 和 .catch(),但仅在错误发生之后
=> 因为.toPromise()直接订阅 Observable,但没有提供错误处理程序,错误会冒泡并导致应用崩溃
=> 如果我们直接链接.catch(err => anyValue)
到返回的 Promise,错误将被捕获,但最终用户将在 .then() 中收到anyValue ,并且无法处理原始错误
=> 如果我们直接链接.catch(err => { someHandling(); return Promise.reject(err); }
到返回的 Promise,因为用户还没有链接他们的.catch(),来自新拒绝的 Promise 的新错误将冒泡并导致应用程序崩溃
因此,我认为没有解决方案,并且上述情况根本无法处理(可以使用 Observable .shareReplay(1) 解决方案来处理它)。
解决方案
推荐阅读
- java - 如何在 Tomcat 8.5 web.xml 中添加 Cache-Control、Pragma 和 expires?
- php - 带索引的 MongoDB 性能查询
- jboss7.x - jboss eap 7 - WFLYCTL0030
- python - 在 PyCharm 中自动标记源文件夹
- react-native - Null 被设置为 Formik 中空字符串的初始值,而反应原生中的 Yup 表单验证
- hasura - 如何在下一个突变中使用动作的返回值?
- python - 使用 BeautifulSoup 抓取维基百科
- amazon-web-services - API 网关 - 同时使用 API 密钥和自定义授权方
- node.js - 如何将 uWebSockets.js 设置到现有的 KOA 服务器中?
- c++ - “cudaOccupancyMaxActiveBlocksPerMultiprocessor”返回的随机占用值