Загрузить изображение из данных формы в S3 с помощью Lambda

Итак, я пишу лямбду, которая будет принимать данные в той или иной форме через прямой POST через шлюз API (на данный момент тестируется с использованием Postman), а затем отправлять это изображение на S3 для хранения. Каждый раз, когда я запускаю его, изображение, загруженное на S3, повреждено и не открывается должным образом. Я видел, как людям приходилось декодировать/кодировать входящие данные, но мне кажется, что я пробовал все, используя Buffer.from. Я только хочу хранить .png или .jpg. Приведенный ниже код не отражает мои попытки использовать кодирование/декодирование Base64, поскольку все они потерпели неудачу. Вот что у меня пока есть -

Образец запроса в почтальоне

{
  image: (uploaded .jpg/.png),
  metadata:  {tag: 'iPhone'}
}

лямбда

const AWS = require('aws-sdk')
const multipart = require('aws-lambda-multipart-parser')
const s3 = new AWS.S3();

exports.handler = async (event) => {
  const form = multipart.parse(event, false)
  const s3_response = await upload_s3(form)
  return {
    statusCode: '200',
    body: JSON.stringify({ data: data })
  }
};

const upload_s3 = async (form) => {
  const uniqueId = Math.random().toString(36).substr(2, 9);
  const key = `${uniqueId}_${form.image.filename}`

  const request = {
    Bucket: 'bucket-name',
    Key: key,
    Body: form.image.content,
    ContentType: form.image.contentType,
  }
  try {
    const data = await s3.putObject(request).promise()
    return data
  } catch (e) {
    console.log('Error uploading to S3: ', e)
    return e
  }
}

РЕДАКТИРОВАТЬ: теперь я пытаюсь сохранить изображение в каталоге /tmp, а затем использовать поток чтения для загрузки в s3. Вот код для этого

функция загрузки s3

const AWS = require('aws-sdk')
const fs = require('fs')

const s3 = new AWS.S3()

module.exports = {
  upload: (file) => {
    return new Promise((resolve, reject) => {
      const key = `${Date.now()}.${file.extension}`
      const bodyStream = fs.createReadStream(file.path)

      const params = {
        Bucket: process.env.S3_BucketName,
        Key: key,
        Body: bodyStream,
        ContentType: file.type
      }

      s3.upload(params, (err, data) => {
        if (err) {
          return reject(err)
        }
        return resolve(data)
      }
      )
    })
  }
}

функция парсера формы

const busboy = require('busboy')

module.exports = {
  parse: (req, temp) => {
    const ctype = req.headers['Content-Type'] || req.headers['content-type']
    let parsed_file = {}

    return new Promise((resolve) => {
      try {
        const bb = new busboy({
          headers: { 'content-type': ctype },
          limits: {
            fileSize: 31457280, 
            files: 1,
          }
        })

        bb.on('file', function (fieldname, file, filename, encoding, mimetype) {
          const stream = temp.createWriteStream()
          const ext = filename.split('.')[1]
          console.log('parser -- ext ', ext)
          parsed_file = { name: filename, path: stream.path, f: file, type: mimetype, extension: ext }
          file.pipe(stream)
        }).on('finish', () => {
          resolve(parsed_file)
        }).on('error', err => {
          console.err(err)
          resolve({ err: 'Form data is invalid: parsing error' })
        })

        if (req.end) {
          req.pipe(bb)
        } else {
          bb.write(req.body, req.isBase64Encoded ? 'base64' : 'binary')
        }

        return bb.end()
      } catch (e) {
        console.error(e)
        return resolve({ err: 'Form data is invalid: parsing error' })
      }
    })
  }
}

обработчик

const form_parser = require('./form-parser').parse
const s3_upload = require('./s3-upload').upload
const temp = require('temp')

exports.handler = async (event, context) => {
  temp.track()
  const parsed_file = await form_parser(event, temp)
  console.log('index -- parsed form', parsed_file)
  const result = await s3_upload(parsed_file)
  console.log('index -- s3 result', result)
  temp.cleanup()
  return {
    statusCode: '200',
    body: JSON.stringify(result)
  }
}

Приведенный выше отредактированный код представляет собой комбинацию другого кода и найденного мной репозитория github, который пытается достичь тех же результатов. Даже с этим решением файл все еще поврежден


person Austin Mehmet    schedule 18.12.2019    source источник
comment
Вы пробовали использовать буфер?   -  person Daniel    schedule 19.12.2019
comment
@Daniel У меня есть - проверьте мои правки, чтобы увидеть, где я сейчас. Пытаюсь загрузить через каталог tmp. Однако файл все еще поврежден   -  person Austin Mehmet    schedule 19.12.2019
comment
@AustinMehmet, какое у вас было сопоставление API GATEWAY для этого?   -  person Gautam Aggrawal    schedule 10.08.2020


Ответы (1)


Разобрался с этим вопросом. Код работает отлично - это была проблема со шлюзом API. Необходимо зайти в настройки шлюза API и установить тип двоичного носителя на multipart/form-data, а затем повторно развернуть API. Надеюсь, это поможет кому-то еще, кто бьется головой о стену, выясняя отправку изображений через данные формы в лямбду.

person Austin Mehmet    schedule 02.01.2020
comment
каково было ваше сопоставление API GATEWAY для этого? - person Gautam Aggrawal; 10.08.2020