你如何正确地承诺请求?

Posted

技术标签:

【中文标题】你如何正确地承诺请求?【英文标题】:How do you properly promisify request? 【发布时间】:2015-04-03 04:37:56 【问题描述】:

Bluebird promisifaction 有点魔力,而request 则是一团糟(它是一个函数,其行为就像一个带有方法的对象)。

具体场景非常简单:我有一个启用了 cookie 的请求实例,通过一个 cookie jar(不使用 request 的全局 cookie 处理程序)。我怎样才能有效地承诺它,以及它支持的所有方法?

理想情况下,我希望能够:

致电request(url) -> 承诺 致电request.getAsync(url) -> 承诺 致电request.postAsync(url, ) -> 承诺

似乎Promise.promisifyAll(request) 无效(因为我收到“未定义 postAsync”)。

【问题讨论】:

全面披露,我是作者:http-as-promised. @idbehold 你只需要透露一些事情,如果你要说的话:P 这不是小事,请考虑在问题跟踪器上打开一个问题。 request(...)request.get(...) 不一样吗?为什么两者都需要? @Esailija 我猜是这样,但这主要是为了避免混淆。我想关键是所有的 API 都是承诺的,而且我没有挂起的回调,因为我没有意识到我需要它。严格来说,是的。两者之一是可选的。 【参考方案1】:

以下应该有效:

var request = Promise.promisify(require("request"));
Promise.promisifyAll(request);

请注意,这意味着 request 不是免费函数,因为 Promisification 与原型方法一起使用,因为事先不知道 this。它仅适用于较新版本的蓝鸟。为 cookie 派生请求对象时,在需要时重复此操作。


如果您使用的是 Bluebird v3,则需要使用 multiArgs 选项:

var request = Promise.promisify(require("request"), multiArgs: true);
Promise.promisifyAll(request, multiArgs: true)

这是因为请求的回调是(err, response, body):Bluebird v3 的默认行为是只接受第一个成功值参数(即response)并忽略其他参数(即body)。

【讨论】:

request 的 cookie 是如何工作的?因为据我所知,它创建了一个 request 的新实例,其中包含一个 cookie 罐 @SecondRikudo 现在可以在新的蓝鸟中使用。请检查一下:) 当您说“较新的版本”时,具体是哪些版本? Bluebird 的承诺对发送到request.get() 回调的responsebody 参数有什么作用?它是否忽略了正文,只使用 response 参数作为 promise 的解析值? @Retsam 这只是multiArgs: true,这是答案的一部分。【参考方案2】:

您可以使用request-promise 模块。

世界著名的 HTTP 客户端“请求”现在符合 Promises/A+。 由蓝鸟提供支持。

安装模块,就可以使用promise风格的request了。

npm install request-promise

【讨论】:

nit:没有 .tapCatch 或其他 bluebird 方法 它使用的不是最新版本的bluebird【参考方案3】:

我举个例子,util 基于 Node.js v11.10.0

import  get, post  from "request";
import  promisify  from "util";

const [getAsync, postAsync] = [get, post].map(promisify);


getAsync("http://***.com")
    .then((statusCode, body) =>  
       //do something 
     );

或者,等效地使用async/await

const foo = async () => 
    const statusCode, body = await getAsync("http://***.com")
    // do something

【讨论】:

请注意,最初的问题是关于 request 对象,而不是它的任何方法,那些(相对)容易。【参考方案4】:

请注意,您不需要第三个回调参数body。它也出现在response 参数上。如果你check the source 可以看到body 只是response.body 的方便。保证它们始终相同。

这意味着本页其他答案中描述的简单承诺足以获取所有响应数据。

const request = require('request')
const  promisify  = require('util')
const rp = promisify(request)

rp('https://example.com').then((body, statusCode) => ...)

这仅适用于传递给回调/承诺的response。传递给响应 eventresponse 对象是标准的 http.IncomingMessage,因此没有 body 属性。

【讨论】:

以上是关于你如何正确地承诺请求?的主要内容,如果未能解决你的问题,请参考以下文章

未捕获(承诺)错误:请求失败,状态码为500

带有请求承诺的 NodeJS 发布请求以进行 Twitch 身份验证

如何正确地打破承诺链?

前端如何尽量正确地处理ajax的异常?

承诺所有并获取请求

如何循环请求承诺 API 请求调用?