Как переслать поток файлов из нескольких частей из fastify-multipart в api третьей части? - PullRequest
0 голосов
/ 27 января 2020

У меня есть узел API, который я создаю, который способен обрабатывать загрузки из нескольких типов файлов (кусков). Этот API основан на библиотеке Fastify, и я уже установил отдельную библиотеку Fastify-Multipart. У меня все работает, включая загрузку файлов из нескольких частей, но часть требований этого API - возможность отправлять запросы другому API. В частности, мне нужно отправить файл загрузки. Я не знаю, на чем написаны их API, но их API для многократной загрузки файлов в основном такой:

sdk.files.uploader(location_id, file_size, "filename.jpg", file)
.then(uploader => uploader.start())
.then(file => { console.log(file) })

Мой код в основном такой:

post: async (request, reply) => {

        // Check for file upload
        if((request.headers['content-type'] && request.headers['content-type'].indexOf('multipart/form-data') !== -1) && request.params.id) {

            const multipart = request.multipart(async (field, stream, filename, encoding, mimetype) => {

                console.log(`folderId: ${request.params.id} filename: ${filename}, 
                            field name: ${field}, encoding: ${encoding}, 
                            mime type: ${mimetype}, file length: ${request.headers['content-length']}`)

                try {
                    let uploader = await sdk.files.uploader(request.params.id, Number(request.headers['content-length']), filename, stream)
                    let file = await uploader.start()
                    console.log(file) //Never reaches this point
                }
                catch(e) {
                    console.log(`An error occurred during upload: ${e.message}`)
                    reply.code(500).send()
                }
                //pump(file, fs.createWriteStream(filename))

            }, (error) => {

                if(error) {
                    console.log(`Error uploading file: ${error.message}`)
                    reply.code(500).send()
                } else {
                    console.log('File upload succeeded') //Upload succeeds but it's just in memory
                    reply.code(201).send()
                }
            })

            multipart.on('field', (key, value) => {
                console.log('form-data', key, value)
            })
        }
    }

Итак, что в основном Я хочу сделать, это передать поток нескольких файлов на этот сторонний API, но делать это таким образом не работает (когда я go на своем сайте, я не вижу файл в папке, где он должно быть). Когда я смотрю на Activity Monitor на моей машине (macOS), я вижу, что процесс узла потребляет 1,2 гигабайта памяти (примерно размер файла). Кто-нибудь знает способ сделать это с помощью Fastify-Multipart (который, я считаю, основан на BusBoy).

1 Ответ

0 голосов
/ 30 января 2020

Я заметил, что ваш обработчик post: async (request, reply) => является асин c, но вы не звоните await, а управляете reply в многочастном обратном вызове. Это может вызвать проблемы. Подробнее см. Разрешение обещания, выполните c.

Я бы посоветовал проверить модуль, по которому вы передаете поток, поскольку он должен использовать подход steam и не сохранять все куски в память.

Вот простой пример:

const fastify = require('fastify')({ logger: true })
const pump = require('pump')

fastify.register(require('fastify-multipart'))

fastify.post('/', function (req, reply) { // this function must not be async
  if (!req.isMultipart()) { // you can use this decorator instead of checking headers
    reply.code(400).send(new Error('Request is not multipart'))
    return
  }

  const mp = req.multipart(handler, onEnd)

  mp.on('field', function (key, value) {
    console.log('form-data', key, value)
  })

  function onEnd (err) {
    if (err) {
      reply.send(err)
      return
    }
    console.log('upload completed')
    reply.code(200).send()
  }

  async function handler (field, file, filename, encoding, mimetype) {
    console.log('.....waiting')
    await wait() // testing async function
    pump(file, ConsoleWriter({ highWaterMark: 1000 }))
  }
})

fastify.listen(3000)

function wait () {
  return new Promise(resolve => {
    setTimeout(resolve, 1000)
  })
}

// A writer that manage the bytes
const { Writable } = require('stream')
function ConsoleWriter (opts) {
  return new Writable({
    ...opts,
    write (chunk, encoding, done) {
      console.log({ chunk: chunk.length, encoding })
      setTimeout(done, 500) // slow simulation
    }
  })
}

Назовите его с помощью:

curl -F file=@"./README.md" -H 'content-type: multipart/form-data' -X POST http://localhost:3000/
...