Upload de imagem codificada em base64 para Amazon S3 via Node.js

99

Ontem eu fiz uma sessão noturna de codificação e criei um pequeno aplicativo node.js / JS (bem, na verdade, CoffeeScript, mas CoffeeScript é apenas JavaScript, então digamos JS).

qual é o objetivo:

  1. cliente envia um canvas datauri (png) para o servidor (via socket.io)
  2. servidor carrega imagem para amazon s3

a etapa 1 está concluída.

o servidor agora tem uma string a la

data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACt...

minha pergunta é: quais são minhas próximas etapas para "transmitir" / fazer upload desses dados para o Amazon S3 e criar uma imagem real lá?

knox https://github.com/LearnBoost/knox parece uma lib incrível para colocar algo no S3, mas o que estou perdendo é a cola entre a sequência de imagem codificada em base64 e a ação real de upload ?

Quaisquer ideias, sugestões e comentários são bem-vindos.

Franz Enzenhofer
fonte
4
Verifique esta resposta: stackoverflow.com/questions/5867534/…
akirk

Respostas:

209

Para pessoas que ainda estão lutando com esse problema. Aqui está a abordagem que usei com o aws-sdk nativo.

var AWS = require('aws-sdk');
AWS.config.loadFromPath('./s3_config.json');
var s3Bucket = new AWS.S3( { params: {Bucket: 'myBucket'} } );

dentro do método do roteador: - ContentType deve ser definido como o tipo de conteúdo do arquivo de imagem

  buf = Buffer.from(req.body.imageBinary.replace(/^data:image\/\w+;base64,/, ""),'base64')
  var data = {
    Key: req.body.userId, 
    Body: buf,
    ContentEncoding: 'base64',
    ContentType: 'image/jpeg'
  };
  s3Bucket.putObject(data, function(err, data){
      if (err) { 
        console.log(err);
        console.log('Error uploading data: ', data); 
      } else {
        console.log('succesfully uploaded the image!');
      }
  });

O arquivo s3_config.json é: -

{
  "accessKeyId":"xxxxxxxxxxxxxxxx",
  "secretAccessKey":"xxxxxxxxxxxxxx",
  "region":"us-east-1"
}
Divyanshu Das
fonte
2
[MissingRequiredParameter: Falta a chave obrigatória 'Chave' nos parâmetros]
Nichole A. Miler
1
Chave: req.body.userId Eu usei userId como chave nos dados de postagem ... já faz muito tempo ... mas você pode declarar qualquer string como chave. Para garantir que os arquivos já presentes não sejam sobrescritos, mantenha a chave exclusiva.
Divyanshu Das
@Divyanshu Obrigado por esse exemplo útil. Eu tenho duas dúvidas: How to make S3 generates a unique KEY to prevent from overriding files?e If I don't set the ContentType, when I download the files I won't be able to get the correct file?quer dizer, vou receber um arquivo tão corrompido? Desde já, obrigado!
alexventuraio
2
O caminho do local @Marklar é basicamente a chave - por exemplo, se o nome do seu intervalo for - bucketone e o nome da chave for xyz.png, o caminho do arquivo será bucketone.s3.amazonaws.com/xyz.png
Divyanshu Das
2
@Divyanshu Obrigado por esta ótima resposta! Isto me ajudou bastante. No entanto, acho que ContentEncoding: 'base64'não está correto porque new Buffer(..., 'base64')decodifica string codificada em base64 em sua representação binária.
Shuhei Kagawa de
17

ok, esta é a resposta de como salvar os dados da tela em um arquivo

basicamente perde assim no meu código

buf = new Buffer(data.dataurl.replace(/^data:image\/\w+;base64,/, ""),'base64')


req = knoxClient.put('/images/'+filename, {
             'Content-Length': buf.length,
             'Content-Type':'image/png'
  })

req.on('response', (res) ->
  if res.statusCode is 200
      console.log('saved to %s', req.url)
      socket.emit('upload success', imgurl: req.url)
  else
      console.log('error %d', req.statusCode)
  )

req.end(buf)
Franz Enzenhofer
fonte
1
O objeto Buffer irá lançar um erro "Buffer não definido" você pode me dar uma solução para isso.
NaveenG
Também estou recebendo o mesmo erro. você tem alguma solução ou não
Krishna
1
@NaveenG Este é um exemplo de nó, talvez você esteja usando JS simples?
Pointi
7

Aqui está o código de um artigo que encontrei, postando abaixo:

const imageUpload = async (base64) => {

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

  const { ACCESS_KEY_ID, SECRET_ACCESS_KEY, AWS_REGION, S3_BUCKET } = process.env;

  AWS.config.setPromisesDependency(require('bluebird'));
  AWS.config.update({ accessKeyId: ACCESS_KEY_ID, secretAccessKey: SECRET_ACCESS_KEY, region: AWS_REGION });

  const s3 = new AWS.S3();

  const base64Data = new Buffer.from(base64.replace(/^data:image\/\w+;base64,/, ""), 'base64');

  const type = base64.split(';')[0].split('/')[1];

  const userId = 1;

  const params = {
    Bucket: S3_BUCKET,
    Key: `${userId}.${type}`, // type is not required
    Body: base64Data,
    ACL: 'public-read',
    ContentEncoding: 'base64', // required
    ContentType: `image/${type}` // required. Notice the back ticks
  }

  let location = '';
  let key = '';
  try {
    const { Location, Key } = await s3.upload(params).promise();
    location = Location;
    key = Key;
  } catch (error) {
  }

  console.log(location, key);

  return location;

}

module.exports = imageUpload;

Leia mais: http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#upload-property

Créditos: https://medium.com/@mayneweb/upload-a-base64-image-data-from-nodejs-to-aws-s3-bucket-6c1bd945420f

Harvey
fonte
4

A resposta aceita funciona muito bem, mas se alguém precisa aceitar qualquer arquivo em vez de apenas imagens, esta regexp funciona muito bem:

/^data:.+;base64,/

Ms01
fonte