将node.js请求包装为promise和管道

时间:2018-06-28 19:37:05

标签: javascript node.js promise request

这是我的情况: 我想使用request库获取一些外部资源(二进制文件),并将其通过管道传输到我自己的应用程序的客户端。如果响应代码为!= 200或到达远程服务器时遇到问题,我想截取并提供自定义错误消息。理想情况下,如果响应很好,我希望保留原始标头。

我使用下面粘贴的第一段代码实现了这一目标。但是,我的整个应用程序都基于Promise API,因此我想使其保持一致并将其包装在promise中。当我这样做时,它不再起作用。首先,我尝试通过request-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');
});

“不工作”是指-没有响应,请求待处理,直到超时。

我已更改代码,以在传递给.pipe()而不是resolve的结果上调用r。它响应客户端,但是响应为空。

最后,我尝试用简单的http.get()替换请求库。这样,服务器将文件返回给客户端,但是缺少标头(例如Content-TypeContent-Length)。

我已经在Google上搜索了很多,尝试了多个请求版本...但没有任何效果。

1 个答案:

答案 0 :(得分:3)

问题是,当触发"response"时,您会创建一个立即解决的新Promise,但是then回调始终是异步执行的,并且在调用它时,文件已到达服务器,并且不再有数据流通过该流。相反,您可以只使用回调的body参数:

request.get('http://foo.bar', function(request, response, body) {
  if(response.statusCode === 200) {
    res.end(body);
  } else {
    res.status(500).end();
  }
});

对于使用流request似乎有点麻烦,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);
});