Readable to Buffer function doesn't work because Readable doesn't emit `end` event

huangapple go评论67阅读模式
英文:

Readable to Buffer function doesn't work because Readable doesn't emit `end` event

问题

以下是您要翻译的内容:

所以我有一个典型的`streamToBuffer`函数

```js
const streamToBuffer = async (stream: NodeJS.ReadableStream): Promise<Buffer> => {
  const chunks: Buffer[] = [];
  return new Promise((resolve, reject) => {
    stream.on('data', (chunk: WithImplicitCoercion<ArrayBuffer | SharedArrayBuffer>) =>
      chunks.push(Buffer.from(chunk)),
    );
    stream.on('error', reject);
    stream.on('end', () => resolve(Buffer.concat(chunks)));
  });
};

就我所知,这是将流转换为缓冲区的NodeJS中通常的方式。

嗯,有一些情况下end事件不会发生。errorclose事件也不会发生。只会触发data事件,然后Promise永远不会被解析/拒绝。

这可能是如何发生的呢?

我认为唯一发生这种情况的情况是使用node-fetch库获取文件时。

const getBinary = async (id: string) => {
  return await fetch(`带有id的内部URL`, {
    method: 'GET',
  })
    .then(async (response) => {
      switch (response.status) {
        case 200:
          return new Readable().wrap(response.body!); // <-- 这个Readable
        case 404:
          throw new NotFound(await response.json());
        default:
          throw a BadGateway(await response.json());
      }
    })
    .catch((err) => {
      throw a InternalServerError(err);
    });
};

我不完全确定这个问题是否只会在像这样获取的流中发生。但就我所能了解,似乎是这样。请注意,并非每次都会发生,只有对于某些id值,某些二进制文件。

一些额外信息:如果我使用浏览器导航或使用curl访问任何存在问题的URL,一切都正常。我可以毫无问题地获取文件。


<details>
<summary>英文:</summary>

So I have a typical `streamToBuffer` function:

```js
const streamToBuffer = async (stream: NodeJS.ReadableStream): Promise&lt;Buffer&gt; =&gt; {
  const chunks: Buffer[] = [];
  return new Promise((resolve, reject) =&gt; {
    stream.on(&#39;data&#39;, (chunk: WithImplicitCoercion&lt;ArrayBuffer | SharedArrayBuffer&gt;) =&gt;
      chunks.push(Buffer.from(chunk)),
    );
    stream.on(&#39;error&#39;, reject);
    stream.on(&#39;end&#39;, () =&gt; resolve(Buffer.concat(chunks)));
  });
};

It's, as far as I know, the usual way of transforming streams into buffers in NodeJS.

Well, there are some instances where the end event doesn't happen. Neither does error or close. Just data event is fired and the promise then never gets resolved/rejected.

How could that be possible?

I think the only situations when this happens are when retrieving a file using the node-fetch library.

const getBinary = async (id: string) =&gt; {
  return await fetch(`an internal URL with the id`, {
    method: &#39;GET&#39;,
  })
    .then(async (response) =&gt; {
      switch (response.status) {
        case 200:
          return new Readable().wrap(response.body!); // &lt;-- This Readable
        case 404:
          throw new NotFound(await response.json());
        default:
          throw new BadGateway(await response.json());
      }
    })
    .catch((err) =&gt; {
      throw new InternalServerError(err);
    });
};

I'm not 100% sure if the issue only happens with a stream obtained like this. But to the best of my ability it appears it is the case. Mind you, not every time. Only for some id values, so certain binaries.

Some extra information: if I navigate with my browser or use curl with any of the problematic URLs everything works fine. I get the file with no issues.

答案1

得分: 1

If you read the doc for readable.wrap() it is not meant for the type of stream in response.body. fetch() returns a WebStream, not the old style nodejs stream that .wrap() is meant to be used with.

在查看readable.wrap()的文档时,它并不适用于response.body中的流类型。fetch()返回的是WebStream,而不是.wrap()旨在与旧式的nodejs流一起使用的类型。

In recent versions of nodejs, you can use Readable.fromWebStream(webStream) to convert from a webStream to a nodejs Readable stream. Nodejs doc.

在较新版本的nodejs中,您可以使用Readable.fromWebStream(webStream)将webStream转换为nodejs可读流。Nodejs 文档

return Readable.fromWeb(response.body);

这里是一个示例:https://css-tricks.com/web-streams-everywhere-and-fetch-for-node-js/#aa-node-streams-interoperability。

在较旧版本的nodejs中,您可以使用支持直接将响应作为nodejs读取流获取的http请求库,如gotaxios

const readStream = got.stream(url);
英文:

If you read the doc for readable.wrap() it is not meant for the type of stream in response.body. fetch() returns a WebStream, not the old style nodejs stream that .wrap() is meant to be used with.

In recent versions of nodejs, you can use Readable.fromWebStream(webStream) to convert from a webStream to a nodejs Readable stream. Nodejs doc.

return Readable.fromWeb(response.body);

Here's an example: https://css-tricks.com/web-streams-everywhere-and-fetch-for-node-js/#aa-node-streams-interoperability.

In older versions of nodejs, you can use an http request library like got or axios that directly supports getting a response as a nodejs readstream.

const readStream = got.stream(url);

huangapple
  • 本文由 发表于 2023年5月22日 23:17:13
  • 转载请务必保留本文链接:https://go.coder-hub.com/76307650.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定