Chupurnov Valeriy
Chupurnov Valeriy
Front End Engineer
Назад

Как через JS отправить файл на сервер и сохранить его на Node JS + Express

/blog/uploads/images/1630535752971-image-image.png

Предположим у нас есть текстовое поле, и когда пользователь копирует туда изображение из буфера, вы хотим его отправить на сервер, сохранить в папку и показать ссылку на изображение в этом самом поле.

Оказалось задачка не из простых.

Клиентская часть

Тут относительно все просто, однако без факапов не обошлось

const textarea = document.querySelector('textarea'); textarea.addEventListener('paste', (e) => { if (e.clipboardData && e.clipboardData.items) { const items = e.clipboardData.items; try { for (let i = 0; i < items.length; i++) { if (items[i].type.indexOf('image') !== -1) { const blob = items[i].getAsFile(); if (blob) { sendFile(blob).then(resp => { textarea.value = resp.filename; }); } } } } catch (e) { alert(e.message); } e.preventDefault() } });
Copy

Ну и собственно функция sendFile:

async function sendFile(file) { const formdata = new FormData(); formdata.append('image', file, 'image.png'); const resp = await fetch('media/upload-image', { method: 'POST', credentials: 'include', headers: { Accept: 'application/json' }, body: formdata }), respData = await resp.json(); if (resp.status !== 200) { throw new Error(respData.message); } return respData; }
Copy

Главное не подавайте в headers лишние заголовки, типа Content-Type. fetch поставит их сам.

Серверная часть

Тут нам на помощь придет либа multer.

npm install --save multer
Copy

Полностью настройку эндпоинтов приводить не буду. Это выходит за рамки статьи.

const express = require('express'); const path = require('path'); const multer = require('multer'); const app = express(); // Функция будет фильтровать файлы, чтобы быть уверенными что загружают только фото const imageFilter = (req, file, cb) => { if (file.mimetype.startsWith('image')) { cb(null, true); } else { cb('Please upload only images.', false); } }; // Создаем хранилище. Просто некая папка, в которую потом можно будет стучать из вне. const storage = multer.diskStorage({ destination: (req, file, cb) => { cb(null, path.resolve(__dirname, '../../uploads/images')); }, filename: (req, file, cb) => { cb(null, `${Date.now()}-image-${file.originalname}`); } }); // И storage и fileFilter необязательны const upload = multer({ storage: storage, fileFilter: imageFilter }); // Тут мы говорим что будем брать только один файл с поля `image` app.use('/upload-image', upload.single('image'), (req, res) => { res.send(req.file); // Тут все данные по файлу, он уже сохранен на диск });
Copy

Ну или настройки проще

const express = require('express'); const multer = require('multer'); const upload = multer({dest: __dirname + '/uploads/images'}); const app = express(); const PORT = 3000; app.use(express.static('public')); app.post('/upload', upload.single('photo'), (req, res) => { if(req.file) { res.json(req.file); } else throw 'error'; }); app.listen(PORT, () => { console.log('Listening at ' + PORT ); });
Copy

Собственно это все. Решил написать статью, так как нормальной информации нигде нет.

Желаю удачи.