14 de dez de 2019 - 3 min de leitura
Upload de arquivos com Nodejs
Enviando arquivos para o servidor
Introdução
Existem algumas estratégias que podem ser adotadas ao realizar uploads de arquivos através da web, e a que vamos ver no post é utilizando o multipart/form-data.
O FormData basicamente nos fornece um conjunto de pares chave/valor, representando os campos de um formulário. Com ele podemos facilmente "anexar" arquivos em um formulário e enviar através de uma requisição para o servidor, que irá armazenar os arquivos.
Para isso vamos precisar de um server nodejs:
const express = require('express');
const server = express();
server.post('/files', (req, res) => {
return res.json({
online: true
});
});
server.listen(3333);
O código acima instância um servidor na porta 3333
da máquina, e cria a rota /files
que será responsável por receber
e armazenar os arquivos.
Para realizar o upload dos arquivos vamos utilizar o Multer. Ele será o middleware responsável por "pegar" os arquivos que estamos enviando na requisição e salvar no servidor.
Multer
Após o servidor estar configurado, vamos instalar o pacote do multer através do npm/yarn: yarn add multer
.
Feito isso, vamos criar um arquivo que irá exportar um objeto com as configurações do multer e passa-las para a instância do middleware:
const multer = require('multer');
const crypto = require('crypto');
const path = require('path');
module.exports = {
/**
* Save files on disk
*/
storage: multer.diskStorage({
/**
* Destination path to save files
*/
destination: path.resolve(__dirname, 'tmp', 'uploads'),
/**
* Filename
*/
filename: (req, file, cb) => {
crypto.randomBytes(8, (err, res) => {
if (err) return cb(err);
return cb(null, res.toString('hex') + path.extname(file.originalname));
});
},
}),
};
Como vamos gravar nossos arquivos em disco, a key storage
do objeto recebe o método diskStorage do multer. O método diskStorage
recebe um objeto com dois valores importantes, são eles:
- Destination: Responsável por receber o path de onde nosso arquivo vai ser salvo;
- filename: Recebe uma função com 3 parâmetros, sendo a requisição(objeto contendo todas informações enviadas pelo client-side), o arquivo e um callback que é executado após a gravação do arquivo;
Se você tem dúvidas sobre callbacks, pode ler meu post tratando o assunto.
Para randomizar o nome do arquivo, utilizei o randomBytes
da crypto. Com isso evitamos conflitos
entre nomes de arquivos.
A função randomBytes
recebe dois parâmetros, sendo err e res. Caso haja algum erro em gerar o nome randômico, o método irá retornar um erro.
Caso tudo ocorra como deveria, o método randomBytes
retorna um nome randômico e salva nosso arquivo em disco com esse nome gerado.
Adicionando o middleware na requisição
Feito as configurações do Multer, basta importa-las no nosso server e passar como um middleware na rota que será responsável por receber os arquivos.
const express = require('express');
const server = express();
/**
* Multer instance and config
*/
const multer = require('multer');
const multerConfig = require('./multer.config'); // ARQUIVO COM AS CONFIGURAÇÕES QUE FIZEMOS NO PASSO ANTERIOR
const upload = multer(multerConfig); // INSTÂNCIA DO MULTER COM NOSSAS CONFIGURAÇÕES
/**
* Use multer to receive files
* Get file value attached in FormData
*/
server.post('/files', upload.single('file'), (req, res) => {
const { file } = req;
if (file) {
return res.json({
file,
fileSaved: true,
});
}
return res.json({
error: 'Erro ao salvar o arquivo.',
fileSaved: false,
});
});
server.listen(3333);
De uma forma resumida: Middlewares são funções/métodos que processam a nossa requisição antes da controller, sendo executadas na ordem em que são passadas.
Veja que quando passamos o multer como middleware da rota /files
, estamos chamando o método single
passando o parâmetro 'file'
pra ele.
Com isso o multer sabe que deve procurar chave 'file' no form que está recebendo, e que essa chave tem o valor de 1 arquivo anexado.
Existem outras formas de trabalhar com o multer além de receber um único arquivo por requisição, você pode conferir na documentação do multer.
Conclusão
Assim que o multer salva o arquivo em disco, ele adiciona a chave file na nossa requisição contendo todas as informações do arquivo que foi salvo. Com essas informações podemos relacionar tabelas em bancos de dados, enviar e-mail, salvar essas informações em alguma tabela etc... Vai depender da sua necessidade.
Aqui você pode ver a estrutura da aplicação que usei para o exemplo enquanto escrevia o artigo.
├── src
│ ├── temp
| | └── uploads
│ └── multer.config.js
| └── server.js
└── README.md
Você pode conferir o código produzido durante a escrita do artigo no meu github.
Dicas, sugestões, conselhos ou melhorias? Você pode entrar em contato comigo pelo meu email ou abrir uma PR no repositório aqui.