Executando verificação de segurança...
2

[Help] Devo criar um Proxy AWS S3 através do Express?

Boas-vindas

Este é o meu primeiro post. Tenho lido diariamente posts de outros usuários, e tenho aprendido bastante com erros, soluções e ideias compartilhadas. Por isso, gostaria também de dar minha contribuição a esta comunidade.

Introdução

Todos os dias, na internet, consumimos diversos tipos de mídia, como texto, imagem e vídeo. No entanto, geralmente eles são servidos de formas diferentes. Por exemplo, um texto pode ser estruturado e enviado no formato JSON, enquanto imagens são geralmente links ou seja também no formato texto , a imagens são fornecidos diretamente do próprio servidor como arquivos estáticos ou armazenados em algum outro provedor.

Tenho uma startup que produz tours virtuais, normalmente exportados como projetos web contendo seu próprio index.html e todos os arquivos necessários, como imagens. Como esses conteúdos não são apenas imagens, soluções como o Cloudinary não atendem às minhas necessidades. Para demonstração, aqui está um exemplo de tour no centro da minha cidade: Cabo Verde, Ilha de São Vicente, Mindelo. Normalmente, um tour pode ultrapassar 100 MB.

Objetivo a alcançar

Quero criar um sistema onde seja possível fazer upload de um tour e adicionar metadados, tornando-o acessível através de um link para meus clientes. Minha primeira ideia foi construir um servidor Node.js com Express para servir os arquivos estaticamente, por exemplo, na rota /tour/:id, com uma pasta contendo todos os tours. Seria possível fazer upload e remoção de tours, proporcionando controle total, incluindo autenticação e visibilidade.

Será que essa é a melhor abordagem?

Essa parece ser uma solução simples, porem, após assistir ao vídeo Why Your Backend Shouldn't Serve Files, percebi que, com arquivos grandes, como imaginei, minha largura de banda no servidor de produção seria bastante exigida.

Por isso, considerei outras soluções, como o AWS S3. Para quem não sabe:

Um bucket do Amazon S3 é um recurso de armazenamento em nuvem pública disponível na plataforma Amazon Web Services (AWS) Simple Storage Service (S3). Ele fornece armazenamento baseado em objeto, onde os dados são armazenados dentro de buckets S3 em unidades chamadas "objetos" em vez de arquivos.

AWS S3 é a solução?

Ao introduzir o S3 na arquitetura, surgem vantagens e desvantagens. Continuando minha pesquisa, encontrei este post: Node.js, Streams, Proxies and Amazon S3 - Medium. Embora o post tenha mais de 10 anos, é uma boa leitura para uma compreensão mais profunda.

Em resumo, discute as seguintes abordagens, destacando vantagens e desvantagens:

  • Link direto para a URL do bucket S3 diretamente
  • Proxy da URL S3 por meio de uma rota Express
  • Uso do AWS SDK / getObject para enviar o arquivo como resposta

Uma vantagem do S3 é que ele pode ser configurado como público ou privado, autenticado ou não. Definindo como public-read, é possível acessar os arquivos diretamente por meio de HTTP/HTTPS usando o nome do bucket e o nome do objeto.

Vantagem: nada toca meu servidor; o usuário final busca os arquivos diretamente da Amazon, melhorando a distribuição de carga e economizando recursos do servidor.

Desvantagem: a URL do meu bucket fica esposto e perco controle sobre o conteúdo servido ou seja acesso pode ser feito sem autenticação, e perco a capacidade de contar visitantes, uma funcionalidade que gostaria de ter.

Proxy da URL S3 por meio de uma rota Express

Em vez de fornecer a URL diretamente, configuramos uma rota no Express. O servidor faz a requisição e encaminha a resposta ao cliente. O código para isso seria:

var request = require('request');
...
app.get('/myimage', function(req, res) {
  request('http://s3-us-west-2.amazonaws.com/my-bucket/myobject.jpg').pipe(res);
});

Vantagem: o conteúdo ainda é publicamente acessível, mas não exposto diretamente aos usuários final. É possível adicionar autenticação básica.

Desvantagem: a largura de banda e os recursos do meu servidor são afetados, pois os arquivos passam pelo servidor.

Uso do AWS SDK / getObject

Aqui, usamos o AWS SDK para uma requisição assinada e autenticada, em vez de simplesmente solicitar o arquivo:

var AWS = require('aws-sdk');
var s3 = new AWS.S3({ region: 'us-west-2' });
...
app.get('/myimage', function(req, res) {
  var imgStream = s3.getObject({
    Bucket: 'my-bucket',
    Key: 'myimage.jpg'
  }).createReadStream();

  imgStream.pipe(res);
});

Conclusão

Confesso que meu conhecimento sobre AWS é básico, mas acredito que uma das melhores alternativas seja o proxy do S3 via Express. No entanto, fico receoso quanto ao custo dessa arquitetura. Espero que este post tenha trazido insights ou que outros já conheçam problemas semelhantes em seus projetos. Embora eu não espere tráfego intenso inicialmente, quero construir algo robusto para evitar grandes mudanças futuramente.

Se alguém com mais experiência já lidou com isso, ficaria feliz em receber sugestões, incluindo alternativas de tecnologias ou provedores.

Carregando publicação patrocinada...
1

Basta utilizar a funcionalidade de presigned URL para gerar um link para acesso unico daquele objeto em questão, sem a necessidade de tornar o objeto publico.

Esse link tem validade definida por você, e pode ser gerado via SDK do AWS.

Fazer o proxy como você mostrou tira toda a vantagem de utilizar o S3.

Inclusive é possível criar uma URL presigned para upload de objetos.

1
1

Olá!

Encontro-me na mesma situção de aprendizado com backend e AWS.

Atualmente, também estou tentando resolver um problema semelhante com o uso do AWS S3, mas ainda não cheguei a uma solução definitiva. Concordo que o proxy via Express parece mais controlado, mas, como você mencionou, a questão do impacto na largura de banda do servidor pode ser um problema.

Vou acompanhar as respostas para aprender com a experiência da comunidade e quem sabe encontrar uma solução mais eficiente!