Consumindo uma stream completa


Em alguns casos é necessário ler a stream de leitura por completa para então poder utilizá-la. Então para isso, deveram ser utilizados os buffers para armazenar temporariamente os dados que estão sendo recebidos pela stream até o fim dela.

import http from 'node:http'
 
 
const server = http.createServer(async (request, response) => {
    const buffers = []
 
    for await (const chunk of request) {
        buffers.push(chunk)
    }
 
    const fullStreamContent = Buffer.concat(buffers).toString()
    console.log(fullStreamContent)
    return response.end(fullStreamContent)
})
 
server.listen(3001)

Nota

A instrução await no for é bem peculiar e é utilizada em situações onde é necessário aguardar que cada interação do loop seja executada para então partir para o próximo loop. No exemplo acima, cada chunk é aguardado ser lido por completo para então passar para o próximo chunk.

O código abaixo simula o envio de dados em larga escala para o servidor criado acima.

import { Readable } from 'node:stream'
 
class OneToHundredStream extends Readable {
    index = 1
 
    _read() {
        const i = this.index++
 
        setTimeout(() => {
            if (i > 5) {
                this.push(null)
            } else {
                const buf = Buffer.from(String(i))
                this.push(buf)
            }
        }, 1_000)
    }
}
 
fetch('http://localhost:3001', {
    method: 'POST',
    body: new OneToHundredStream(),
    duplex: 'half'
}).then(response => {
    return response.text()
}).then(data => {
    console.log(data)
})

Para subir o servidor e então executar o arquivo que simula o envio dos dados, execute os seguintes comandos:

$ node src/consumindo-streams/stream-http-server.js
$ node src/consumindo-streams/fake-upload-to-http-stream.js

Como saída nos logs do servidor, teremos:

12345

Referências