2.1 Multer
Multer działa jak program pośredniczący (middleware) dla frameworka Express, który jest wykorzystywany przy ładowaniu plików do opracowywania multipart/form-data. W gruncie rzeczy jest tak naprawdę warstwą abstrakcji dla pakietu niższego poziomu busboy i jest od niego prostszy w użyciu. Multer nie obsługuje żadnego innego typu formularza, niż multipart/form-data.
Instalacja:
npm install -S multer
Multer dodaje do obiektu request.body obiekt file (lub files). Obiekt body zawiera wartość pól tekstowych formularza, obiekt file (files) zawiera plik lub pliki ładowane przez formularz.
Pełen kod naszej aplikacji jest następujący:
const createError = require('http-errors');
const express = require('express');
const path = require('path');
const fs = require('fs').promises;
const app = express();
const multer = require('multer');
const uploadDir = path.join(process.cwd(), 'uploads');
const storeImage = path.join(process.cwd(), 'images');
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, uploadDir);
},
filename: (req, file, cb) => {
cb(null, file.originalname);
},
limits: {
fileSize: 1048576,
},
});
const upload = multer({
storage: storage,
});
app.post('/upload', upload.single('picture'), async (req, res, next) => {
const { description } = req.body;
const { path: temporaryName, originalname } = req.file;
const fileName = path.join(storeImage, originalname);
try {
await fs.rename(temporaryName, fileName);
} catch (err) {
await fs.unlink(temporaryName);
return next(err);
}
res.json({ description, message: 'Plik załadowany pomyślnie', status: 200 });
});
// catch 404 and forward to error handler
app.use((req, res, next) => {
next(createError(404));
});
app.use((err, req, res, next) => {
res.status(err.status || 500);
res.json({ message: err.message, status: err.status });
});
const isAccessible = path => {
return fs
.access(path)
.then(() => true)
.catch(() => false);
};
const createFolderIsNotExist = async folder => {
if (!(await isAccessible(folder))) {
await fs.mkdir(folder);
}
};
const PORT = process.env.PORT || 3000;
app.listen(PORT, async () => {
createFolderIsNotExist(uploadDir);
createFolderIsNotExist(storeImage);
console.log(`Server running. Use on port:${PORT}`);
});
Pakiet dostarcza następujących informacji dla każdego załadowanego pliku:
| Klucz | Opis | Uwagi |
| fieldname | Nazwa pola, wprowadzona w formularzu | |
| originalname | Nazwa pliku na komputerze użytkownika | |
| encoding | Kodowanie pliku | |
| mimetype | Mime-typ pliku | |
| size | Rozmiar pliku w bajtach | |
| destination | Katalog, w którym będzie zapisany plik | DiskStorage |
| filename | Nazwa pliku bez destination | DiskStorage |
| path | Pełna ścieżka do ładowanego pliku | DiskStorage |
| buffer | Buffer z całego pliku | MemoryStorage |
Tworzymy opcje przestrzeni dyskowej DiskStorage w której przechowywane będą pliki:
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, uploadDir);
},
filename: (req, file, cb) => {
cb(null, file.originalname);
},
limits: {
fileSize: 1048576,
},
});
Przy pomocy opcji, definiujemy funkcje dla miejsca docelowego pliku destination i nazwy pliku filename i określamy, gdzie będzie znajdował się plik po ładowaniu:
- destination wykorzystuje się, aby określić katalog, w którym będą umieszczone pliki;
- filename wykorzystuje się, aby określić, jak będzie nazwany plik wewnątrz katalogu. Jeśli nazwa pliku filename nie jest określona, to do każdego pliku będzie przypisana losowa nazwa bez rozszerzenia pliku.
W parametrach każdej funkcji jest zapytanie (req) i zbiór informacji o pliku (file) np:
{
fieldname: 'picture',
originalname: 'nazwa_pliku.jpg',
encoding: '7bit',
mimetype: 'image/jpeg'
}
Istnieje również obiekt limits ustanawiający ograniczenia rozmiaru pliku. W pełni pokrywa się on z metodami pakietu busboy, a tutaj możesz zobaczyć pełną listę metod.
W naszym przykładzie ustawiliśmy maksymalny rozmiar pliku na 1 MB (1024 * 1024 bajty = 1048576 = 1MB).
Tworzymy egzemplarz multer:
const upload = multer({
storage: storage,
});
Dalej wykorzystujemy program pośredniczący:
upload.single('picture');
Ładuje on jeden plik o nazwie picture do tymczasowego folderu uploads, a informacja o pliku będzie zapisana w req.file.
Wewnątrz middleware przenosimy plik do folderu stałego zapisu images.
Pełny kod przykładu znajduje się na Github Gist