Javascript 将node.js请求包装到promise和piping中
以下是我的设想: 我想使用库获取一些外部资源(二进制文件),并通过管道将其传输到我自己应用程序的客户端。如果响应代码为!=200或到达远程服务器时出现问题,我想截获并提供自定义错误消息。理想情况下,若响应良好,我希望保留原始标题 我能够通过下面粘贴的第一段代码实现这一点。然而,我的整个应用程序都是基于Promise API的,所以我想让它保持一致,并将其包装在Promise中。当我这么做的时候,它就不起作用了。首先,我试图做到这一点,但没有成功。然后我试着自己准备一个非常简单的例子,但还是没有运气 工作示例Javascript 将node.js请求包装到promise和piping中,javascript,node.js,promise,request,Javascript,Node.js,Promise,Request,以下是我的设想: 我想使用库获取一些外部资源(二进制文件),并通过管道将其传输到我自己应用程序的客户端。如果响应代码为!=200或到达远程服务器时出现问题,我想截获并提供自定义错误消息。理想情况下,若响应良好,我希望保留原始标题 我能够通过下面粘贴的第一段代码实现这一点。然而,我的整个应用程序都是基于Promise API的,所以我想让它保持一致,并将其包装在Promise中。当我这么做的时候,它就不起作用了。首先,我试图做到这一点,但没有成功。然后我试着自己准备一个非常简单的例子,但还是没有运
var r = request.get('http://foo.bar');
r.on('response', result => {
if (result.statusCode === 200) {
r.pipe(res);
} else {
res.status(500).send('custom error message')
}
});
r.on('error', error => res.status(500).send('custom error message');
var r;
return new Promise((resolve, reject) => {
r = request.get('http://foo.bar');
r.on('response', result => {
if (result.statusCode === 200) {
resolve();
} else {
reject()
}
});
r.on('error', reject);
}).then(() => {
r.pipe(res);
}).catch(() => {
res.status(500).json('custom error message');
});
不起作用示例
var r = request.get('http://foo.bar');
r.on('response', result => {
if (result.statusCode === 200) {
r.pipe(res);
} else {
res.status(500).send('custom error message')
}
});
r.on('error', error => res.status(500).send('custom error message');
var r;
return new Promise((resolve, reject) => {
r = request.get('http://foo.bar');
r.on('response', result => {
if (result.statusCode === 200) {
resolve();
} else {
reject()
}
});
r.on('error', reject);
}).then(() => {
r.pipe(res);
}).catch(() => {
res.status(500).json('custom error message');
});
我所说的“不工作”是指没有响应,请求在超时之前处于挂起状态
我已将传递到resolve
的结果改为调用.pipe()
,而不是r
。它响应客户机,但响应为空
最后,我尝试用简单的http.get()
替换请求库。这样,服务器将文件返回给客户端,但缺少头(如内容类型
或内容长度
)
我在谷歌上搜索了很多,尝试了几个请求版本。。。问题是,当触发
“response”
时,您创建了一个立即解决的新承诺,但是然后回调总是异步执行,当调用它时,文件已到达服务器,并且不再有数据流过流。相反,您可以只使用回调函数的body
参数:
request.get('http://foo.bar', function(request, response, body) {
if(response.statusCode === 200) {
res.end(body);
} else {
res.status(500).end();
}
});
对于使用streamsrequest
似乎有点问题,axios
似乎做得更好:
axios.get("http://foo.bar"', {
validateStatus: status => status === 200,
responseType: "stream"
}).then(({data: stream}) => {
stream.pipe(res);
}).catch(error => {
res.status(500).json(error);
});
问题是,当触发“response”
时,您创建了一个立即解决的新承诺,但是然后回调总是异步执行的,当它被调用时,文件已经到达服务器,并且不再有数据流过流。相反,您可以只使用回调函数的body
参数:
request.get('http://foo.bar', function(request, response, body) {
if(response.statusCode === 200) {
res.end(body);
} else {
res.status(500).end();
}
});
对于使用streamsrequest
似乎有点问题,axios
似乎做得更好:
axios.get("http://foo.bar"', {
validateStatus: status => status === 200,
responseType: "stream"
}).then(({data: stream}) => {
stream.pipe(res);
}).catch(error => {
res.status(500).json(error);
});
在解决承诺之前,您是否尝试过.pipe()?在管道中使用承诺有什么意义?他们的目的是相反的。管道允许不等待整个响应完成。是的,它可以工作。那么唯一的问题是当我想在Then()
中插入管道时,我真正想要的是在应用程序的不同部分获得远程资源和管道,并且承诺会使分离变得容易。Estus,我不确定我是否正确理解你,但是。。。我想我必须等待,因为我想检查状态码?@xersiee理想情况下,你只想等待状态码,但一旦它在那里并且是2xx,你就不想等待整个响应到达,只需在数据进入时将其流式传输到目的地-所以原始方法对我来说很好!在解决承诺之前,您是否尝试过.pipe()?在管道中使用承诺有什么意义?他们的目的是相反的。管道允许不等待整个响应完成。是的,它可以工作。那么唯一的问题是当我想在Then()
中插入管道时,我真正想要的是在应用程序的不同部分获得远程资源和管道,并且承诺会使分离变得容易。Estus,我不确定我是否正确理解你,但是。。。我想我必须等待,因为我想检查状态码?@xersiee理想情况下,你只想等待状态码,但一旦它在那里并且是2xx,你就不想等待整个响应到达,只需在数据进入时将其流式传输到目的地-所以原始方法对我来说很好!谢谢你的提示。我可能会去的。但有一个小问题需要跟进——如果您所写的是真的,那么为什么在触发响应后也执行管道时,第一个示例中的所有操作都有效?您能否进一步解释为什么该代码不起作用?你的意思是说文件在注册r.on('response',…)
之前就已经到达了?@dasfdsa这是由于承诺的异步性,我编辑了一些措辞precise@xersiee:在第一个示例中(无承诺),将立即调用r.pipe
,而如果在解析承诺后调用它,它将出现在事件循环的下一轮中。似乎描述了一种类似的情况,即在解析承诺后调用管道之前数据丢失。(request
在这方面有很多未解决的问题-只要看看问题的数量和GitHub中打开的PRs,我建议考虑一个替代方案。)您还提到,request promise
也不起作用-您尝试了什么?此答案中的解决方案失去了流式处理的好处:它首先将整个响应体加载到内存中,然后才将其发送到res
,这可能是非常低效的,并且只有当数据的大小足够小时才足够好。(参见示例)感谢您的提示。我可能会去的。但有一个小问题需要跟进——如果您所写的是真的,那么为什么在触发响应后也执行管道时,第一个示例中的所有操作都有效?您能否进一步解释为什么该代码不起作用?你的意思是说文件在注册r.on('response',…)
之前就已经到达了?@dasfdsa这是由于承诺的异步性,我编辑了一些措辞precise@xersiee:在第一个示例中(无承诺),将立即调用r.pipe
,而如果在解析承诺后调用它,它将出现在事件循环的下一轮中。似乎