No se puede canalizar la secuencia de lectura del objeto s3 a la solicitud PUT

Tengo un escenario simple. Necesito leer un objeto de S3 y canalizar su salida a la solicitud PUT . Aquí está mi código utilizando la solicitud .

 // client.js let AWS = require('aws-sdk') let request = require('request') let bucket = 'my_bucket' let filename = 'path/to/file.zip' let host = 'localhost' let port = 8080 let s3 = new AWS.S3({ . . . }) let readStream = s3.getObject({ Bucket: bucket, Key: filename }).createReadStream() let formData = { applicationType: 'my_app_type', applicationName: 'my_app_name', upload: { value: readStream, options: { filename: 'my_file_name.zip', contentType: 'application/zip' } } } request.put({ url: 'http://' + host + ':' + port + '/bootstrap', formData: formData }, function (error, response, body) { if (error) throw error console.log(body) }) 

Y, aquí está mi código server.js .

 // server.js let http = require('http') let Busboy = require('busboy') let events = require('events') let fs = require('fs') let host = 'localhost' let port = 8080 let compressedCodeLocation = './code.zip' let handleRequest = function (request, response) { let eventEmitter = new events.EventEmitter() let inputStreamWriter = fs.createWriteStream(compressedCodeLocation) inputStreamWriter.on('finish', function () { eventEmitter.emit('input.stream.saved') }) let busboy = new Busboy({ headers: request.headers }) busboy.on('file', function (field, file) { file.pipe(inputStreamWriter) }) busboy.on('field', function (field, val) { console.log(field + ': ' + val) }) eventEmitter.on('input.stream.saved', function () { let stats = fs.statSync(compressedCodeLocation) response.statusCode = 200 response.end(JSON.stringify(stats)) }) request.pipe(busboy) } let server = http.createServer(handleRequest) server.listen(port, host, function () { console.log('Server started on ' + host + ':' + port) }) let handleShutdown = function () { server.close(function () { console.log('Server stopped on ' + host + ':' + port) }) } process.on('SIGTERM', handleShutdown) process.on('SIGINT', handleShutdown) 

Server recibe los siguientes headers :

 { host: 'localhost:8080', 'content-type': 'multipart/form-data; boundary=--------------------------870259812928253745629174', 'content-length': '465', connection: 'close' } 

Estoy recibiendo este error en el lado del Server :

 File [upload] got 58 bytes events.js:160 throw er; // Unhandled 'error' event ^ Error: Unexpected end of multipart data at /pots/cnc/node_modules/dicer/lib/Dicer.js:62:28 at _combinedTickCallback (internal/process/next_tick.js:67:7) at process._tickCallback (internal/process/next_tick.js:98:9) 

Y, el Client recibe el siguiente error:

 Error: read ECONNRESET at exports._errnoException (util.js:1018:11) at TCP.onread (net.js:568:26) 

Lo curioso es que, si primero createReadStream el archivo localmente y luego createReadStream para ese archivo local, funciona:

 let formData = { ... upload: { value: fs.createReadStream(localPath + "/" + filename), options: { ... } } }; 

Tuve problemas para usar la solicitud. Pero me funcionó bien. Prueba esto:

 const {S3} = require('aws-sdk'), got = require('got'), FormData = require('form-data'), ; const form = new FormData(), readStream = s3.getObject({ Bucket: bucket, Key: filename }).createReadStream() ; form.append('applicationType', 'my_app_type') form.append('applicationName', 'my_app_name') form.append('upload', readStream,{ filename: 'my_file_name.zip', contentType: 'application/zip' }) got.put('http://' + host + ':' + port + '/bootstrap', {body: form}) 

Solución 2:

Otra respuesta que encontré hoy es mucho más simple. Simplemente use la propiedad knownLength para que el módulo de solicitud conozca el tamaño del archivo de antemano.

 upload: { value: readStream, options: { filename: 'my_file_name.zip', contentType: 'application/zip' knownLength: 423424 } } 

Solución 1

Esta solución está utilizando el módulo de solicitud , en caso de que no quiera introducir una nueva biblioteca en su código.

Resolví esta pregunta con ayuda de la respuesta @metakungfu . Por favor redirigir cualquier voto a su respuesta.

Necesitaba restablecer el formulario del módulo require al form-data módulo de form-data de formulario. Como se indica en la documentación de la request :

Para casos avanzados, puede acceder al objeto de datos de formulario a través de r.form() .

Una vez que se establece un nuevo formulario en mi solicitud (que creo que reescribe el límite de varias partes), canalizo los datos de mi formulario a mi solicitud. Ver referencia .

 let AWS = require('aws-sdk') let FormData = require('form-data') let request = require('request') let bucket = 'ppi-uploads' let filename = 'introduction.zip' let host = 'localhost' let port = 8080 let s3 = new AWS.S3({ . . . }) let readStream = s3.getObject({ Bucket: bucket, Key: filename }).createReadStream() let form = new FormData() form.append('applicationType', 'html') form.append('applicationName', 'introduction') form.append('upload', readStream, { filename: 'introduction.zip', contentType: 'application/zip' }) let putRequest = request.put({ url: 'http://' + host + ':' + port + '/bootstrap', headers: form.getHeaders() }, function (error, response, body) { if (error) throw error console.log(body) }) form.pipe(putRequest)