Request: O upload de arquivos funciona apenas com fluxos de leitura padrão

Criado em 28 dez. 2016  ·  26Comentários  ·  Fonte: request/request

Eu tenho tentado fazer upload de um arquivo (usando solicitação POST multipart) que está dentro do arquivo TAR (eu uso a biblioteca tar-stream para obter fluxo para um arquivo específico dentro do arquivo TAR). Mas sempre falha com o erro ECONNRESET. Depois de um pouco de experiência, parece que ele só pode fazer upload de fluxos construídos diretamente com fs.createReadStream e falha com erro irrelevante para todos os outros fluxos.

Aqui está um exemplo mínimo para reproduzir o problema. Se o fluxo PassThrough for passado para formData , ocorrerá o seguinte erro:

ERROR { Error: socket hang up
    at createHangUpError (_http_client.js:254:15)
    at Socket.socketOnEnd (_http_client.js:346:23)
    at emitNone (events.js:91:20)
    at Socket.emit (events.js:185:7)
    at endReadableNT (_stream_readable.js:974:12)
    at _combinedTickCallback (internal/process/next_tick.js:74:11)
    at process._tickCallback (internal/process/next_tick.js:98:9) code: 'ECONNRESET' }

Servidor:

var http = require('http');

http.createServer(function (request, response) {                                                                                    
    request.on('data', function(chunk) {
      console.log(chunk.length);
    });    
    request.on('end', function() {
      response.writeHead(200, "OK", {'Content-Type': 'text/html'});
      response.end();
    });                                                           
}).listen(8077);

Cliente:

var request = require('request');
var fs = require('fs');
var PassThrough = require('stream').PassThrough;

var rs = fs.createReadStream('some_file.bin'), pt = new PassThrough();  
rs.pipe(pt);    
request({
    'method': 'POST',
    'url': 'http://127.0.0.1:8077',
    'formData': {
        'uploaded_file': pt
    }
}, function (err, httpResponse, body)
{
    if (err)
        console.log('ERROR', err);
    else
        console.log({ 'statusCode': httpResponse.statusCode, 'body': body });
});

Comentários muito úteis

Consegui fazer o upload do meu arquivo usando o buffer diretamente. Você só precisa especificar informações relacionadas ao arquivo (nome do arquivo, tipo, ...)

var formData = {
  'file': {
    value: buffer,
    options: {
      filename: file.filename,
      contentType: file.mimetype
    }
  }
}

https://github.com/form-data/form-data#alternative -submission-methods

Todos 26 comentários

Eu tenho o mesmo problema quando tento envolver um Buffer em um fluxo de leitura para carregá-lo como uma solicitação válida de várias partes.

Também venho tentando encontrar uma maneira de contornar esse problema há algum tempo e experimentei os mesmos problemas mencionados acima. Alguém encontrou uma solução para isso? Talvez isso seja realmente um bug com o pacote form-data?

Mesmo problema aqui, tenho uma string base64 e preciso enviá-la como um arquivo. Eu converto meu base64 em um buffer e, assim como @philipp-spiess, eu o envolvo em um fluxo de leitura, mas não funciona. Vocês encontraram um trabalho ao redor?

atualização: por enquanto minha solução está usando bhttp (https://www.npmjs.com/package/bhttp) que usa streams2

Consegui fazer o upload do meu arquivo usando o buffer diretamente. Você só precisa especificar informações relacionadas ao arquivo (nome do arquivo, tipo, ...)

var formData = {
  'file': {
    value: buffer,
    options: {
      filename: file.filename,
      contentType: file.mimetype
    }
  }
}

https://github.com/form-data/form-data#alternative -submission-methods

@PierreCavalet , tentei dessa maneira, mas infelizmente não funcionou.

Minha "solução" foi simplesmente não usar a biblioteca request e implementar o POST multipart usando o serviço http nodejs.

@PierreCavalet Seu buffer já tem texto codificado? Para mim, o buffer é um blob binário que quebrou a codificação da solicitação (já que aparentemente não foi codificado corretamente).

Edit: Aparentemente, nenhuma codificação especial é necessária, talvez apenas um deslocamento de bit errado?! De qualquer forma lembro que o erro foi o servidor reclamando de um byte inválido.

@philipp-spiess meu buffer é criado com:

Buffer.from(base64string, 'base64')

Então, sim, é um blob binário. A documentação diz que cria um novo Buffer contendo a string JavaScript fornecida. Se fornecido, o parâmetro encoding identifica a codificação de caracteres da string.

@PierreCavalet O Buffer que eu estava usando era direto de multer , um middleware de upload de arquivo para express .

@philipp-spiess Isso é estranho. Minha string base64 vem de uma codificação base64 de um buffer, e esse buffer é direto do upload do meu arquivo. (A codificação é feita por outro serviço, por isso "codificamos e decodificamos" para "nada"). Portanto, deve funcionar para você também.

@samkelly muito obrigado por sua recomendação de usar bhttp . Funciona perfeitamente!

@bchr02 por exemplo!

Rastreou este erro: acaba sendo um problema com a função _length_retriever do form-data . Se você tem um fluxo que não é um dos 3 fluxos totalmente compreendidos (basicamente arquivos com um campo fd , respostas HTTP ou fluxos de saída de solicitação), você basicamente precisa mentir para os dados do formulário para fazer isso a coisa certa (e você precisa ter o comprimento preciso do byte do fluxo). Para fazer funcionar, acabei fazendo assim:

var buffer = Buffer.from(base64string, 'base64');
buffer['httpVersion'] = true;
buffer.headers = { 'content-length': 64 }
var formData = {
  'file': {
    value: buffer,
    options: {
      filename: file.filename,
      contentType: file.mimetype
    }
  }
}

Muito importante: você DEVE especificar o campo filename no options , caso contrário você terá outra exceção.

Se você puder especificar as opções de arquivo, poderá especificar options.knownLength com o comprimento de byte do fluxo de arquivo e ele será selecionado pelo FormData.

É mencionado no leia-me do FormData, embora não seja muito divulgado. Request não menciona isso em nenhum lugar agora, até agora eu posso dizer.

Ah, isso funcionou: ensine-me a fazer qualquer depuração às 2 da manhã. Eu poderia jurar que tentei knownLength e obtive uma exceção, mas isso pode ter sido a falta do campo filename causando caos.

isso não funciona para a minha situação, porque estou carregando algo que faz parte de um fluxo gzip, portanto, não sei o comprimento.

@ sam0x17 Na verdade, não será, até onde eu sei, a solicitação não suporta atualmente transfer-encoding: chunked , portanto, seu uso de bhttp.

Veja também

marca

Eu enfrentei o mesmo problema, aqui está minha solução alternativa, usando diretamente o módulo http.

const streamSample = fs.createReadStream('data.csv').pipe(passThrough);

const formHTTP = new FormData();
formHTTP.append('sampleFieldText', 'text-sample');
formHTTP.append('myFile', streamSample);

const requestToSend = http.request({
    method: 'post',
    host: 'localhost',
    path: '/http',
    headers: formHTTP.getHeaders()
});

formHTTP.pipe(requestToSend);

requestToSend.on('response', (res) => {
    console.log('HTTP response', res.statusCode);
});

requestToSend.on('error', (e) => {
    console.log('ERROR HTTP', e);
});

@BenjD90
Usei sua solução alternativa, mas parece que o fluxo não é enviado. Estou usando multer na extremidade receptora, se for de alguma relevância.

@Ncifra Tenho certeza de que minha solução funciona, porque a uso todos os dias no meu projeto atual.
Você pode testar sua transmissão em https://beceptor.com/ ;)

Na verdade, resolvi isso seguindo: https://github.com/form-data/form-data/issues/356#issue -234978025
Aqui está meu problema original relacionado ao problema: https://github.com/form-data/form-data/issues/409

@BenjD90 Atualmente reverti o código e não posso testá-lo, pois era um recurso muito atrasado no projeto em que estou trabalhando. Talvez eu estivesse perdendo alguma coisa, já que todos esses testes criaram muito código esparso. No entanto, eu registrei as solicitações, e o objeto form-data parecia ter o arquivo nele, mas multer não parecia recebê-lo, enquanto os outros dados não binários estavam sendo enviados corretamente.

Este problema foi marcado automaticamente como obsoleto porque não teve atividade recente. Será fechado se não ocorrer mais nenhuma atividade. Obrigado por suas contribuições.

@stale Este bug está presente em aço e deve ser corrigido no dia ^^

Sim, concordo, é tão importante agora como era naquela época. Basicamente, estou esperando que isso seja corrigido antes de usar request novamente em vez de bhttp . Este é um recurso básico da API de streams e streams2 e deve ser totalmente suportado por request .

Esta página foi útil?
0 / 5 - 0 avaliações