Aqui vamos ver como enviar um formulário com arquivos e salvá-los no servidor.
No lado do cliente, vamos criar um formulário simples com alguns inputs no html:
<form>
<label for="name"> Nome: </label>
<input type="text" id="name" name="name" />
<br /><br />
<label for="photo"> Foto: </label>
<input type="file" id="photo" name="photo" />
<br /><br />
<input type="submit" value="Enviar" />
</form>Vamos capturar o evento de submit do formulário usando o javascript:
const form = document.querySelector('form');
form.addEventListener('submit', (event) => {
event.preventDefault();
// Código para enviar o formulário
}A Fetch API é fácil de utilizar e trabalha com promisses, então dá pra encadear as respostas e não transformar o código em uma pirâmide da desgraça.
fetch('http://localhost:3000/upload', {
method: 'POST',
body: new FormData(form),
})
.then((response) => {
return response.text();
})
.then((data) => {
console.log('Resposta:', data);
})
.catch((err) => {
console.error(err);
});Temos que colocar esse código dentro do event listener do formulário.
XMLHttpRequest trabalha com eventos, mas também é uma opção boa, pois é possível capturar o progresso do upload, possibilitando criarmos uma barra de progresso ou algo do tipo.
const xhr = new XMLHttpRequest();
xhr.open('POST', 'http://localhost:3000/upload', true);
xhr.onload = () => {
console.log('Resposta:', xhr.response, 'Status:', xhr.status);
};
xhr.onerror = (error) => {
console.error(error);
};
xhr.upload.onprogress = (event) => {
if (event.lengthComputable) {
const completed = event.loaded / event.total;
console.log(completed);
}
};
xhr.upload.onloadstart = (event) => {
console.log('Upload iniciado.');
};
xhr.upload.onloadend = (event) => {
console.log('Upload concluído.');
};
xhr.send(new FormData(form));No server vamos utilizar o formidable e o express.
Instalação:
npm install formidable express
Utilizando:
const express = require('express');
const formidable = require('formidable');
const fs = require('fs');
const path = require('path');
const app = express();
app.listen(3000, () => {
console.log('Listening at port 3000.');
});
app.post('/upload', (req, res) => {
const form = formidable.IncomingForm();
form.parse(req, (err, fields, files) => {
if (err) {
res.status(500);
res.send('Erro:', err);
return;
}
if (files.photo) {
const oldPath = files.photo.path;
const newPath = path.join(__dirname, 'uploads', files.photo.name);
fs.rename(oldPath, newPath, (error) => {
if (error) throw error;
});
}
res.send('Upload com sucesso!');
});
});Se o cliente enviou um imagem.png, por exemplo, ele será salvo em /uploads/imagem.png dentro do servidor nesse exemplo.
Aqui eu não usei o campo de nome do formulário que chegou, mas ele é acessível em fields.name.
Do photo eu só usei o name e path, mas também da pra usar size, type, hash, e lastModifiedDate.
Para inputs do formulário que aceitam multiplos arquivos, como:
<input id="files" type="file" id="images" name="images" multiple />Podemos utilizar o formidable desta forma:
app.post('/upload', (req, res) => {
const form = formidable.IncomingForm();
form.on('field', function (field, value) {
console.log(`field: ${field} - ${value}`);
// Código que faz algo com o field
});
form.on('file', function (field, file) {
console.log(`file: ${field} - ${file.name}`);
// Código que faz algo com o file
});
form.on('end', function () {
console.log('Finish');
res.send('Upload finalizado.');
});
form.parse(req);
});field: name - Rodrigo
file: images - IMG_0004.jpg
file: images - IMG_0023.jpg
Finish


