简体   繁体   English

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

[英]Wrapping node.js request into promise and piping

Here is my scenario: I want to get some external resource (binary file) using request library and pipe it to the client of my own application. 这是我的情况:我想使用请求库获取一些外部资源(二进制文件),并将其通过管道传递到我自己的应用程序的客户端。 If response code is != 200 or there are problems reaching remote server, I want to intercept and provide custom error message instead. 如果响应代码为!= 200或到达远程服务器时遇到问题,我想截取并提供自定义错误消息。 Ideally, if response is fine, I want original headers to be preserved. 理想情况下,如果响应很好,我希望保留原始标头。

I was able to achieve that with the first piece of code I've pasted below. 我通过下面粘贴的第一段代码实现了这一目标。 However, my whole application is based on Promise API so I wanted to make it consistent and wrap it in promise too. 但是,我的整个应用程序都基于Promise API,因此我想使其保持一致并将其包装在promise中。 And when I do that, it no longer works. 当我这样做时,它不再起作用。 Firstly, I tried to achieve that with request-promise , without success. 首先,我尝试通过request-promise实现这一目标,但没有成功。 Then I tried to prepare very simple example on my own, still no luck. 然后,我尝试自己编写一个非常简单的示例,仍然没有运气。

Working example 工作实例

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');

Not working example 不工作的例子

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');
});

By 'not working' I mean - no response is delivered, request is pending until timeout. 所谓“不工作”,是指-未传递任何响应,请求处于待处理状态,直到超时。

I've changed the code to call .pipe() on result passed to resolve instead of r . 我已经更改了代码,以在传递给resolve而不是r结果上调用.pipe() It responds to client, but response is empty then. 它响应客户端,但是响应为空。

At the end, I've tried replacing request lib with simply http.get() . 最后,我尝试用简单的http.get()替换请求库。 And with that, server returns file to the client, but headers (like Content-Type or Content-Length ) are missing. 这样,服务器将文件返回给客户端,但是缺少标头(如Content-TypeContent-Length )。

I've googled a lot, tried several request versions... and nothing is working. 我已经在Google上搜索了很多,尝试了多个请求版本...但没有任何效果。

The problem is that when "response" is triggered, you create a new promise that resolves immeadiately, but the then callback is always executed asynchronously, and when it gets called the file has arrived at the server, and there is no data flowing through the stream anymore. 问题是,当触发"response"时,您会创建一个立即解决的新承诺,但是then回调总是异步执行的,并且当它被调用时,文件已到达服务器,并且没有数据流过流了。 Instead you could just use the body parameter of the callback: 相反,您可以只使用回调的body参数:

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

For working with streams request seems a bit buggy, axios seems to do it better: 对于使用流request似乎有点axiosaxios似乎做得更好:

axios.get("http://foo.bar"', {
  validateStatus: status => status === 200,
  responseType: "stream"
}).then(({data: stream}) => {
  stream.pipe(res);
}).catch(error => {
   res.status(500).json(error);
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM