middleware multer

Multer è un middleware node.js per gestire multipart/form-data, che viene utilizzato principalmente per caricare file. È scritto in cima a busboy per la massima efficienza.

NOTA: Multer non elaborerà alcun modulo che non sia multipart (multipart/form-data).

Installazione

Terminal window
npm install multer

Note

multer does not include its own TypeScript type definitions. If you use TypeScript, also install the community-maintained types from DefinitelyTyped as a development dependency:

Terminal window
npm install --save-dev @types/multer

Utilizzo

Multer aggiunge un oggetto body e un oggetto file o files all’oggetto request. L’oggetto body contiene i valori dei campi di testo del modulo, l’oggetto file o files contiene i file caricati attraverso il modulo.

Esempio di utilizzo di base:

Non dimenticare il enctype="multipart/form-data" nel tuo modulo.

<form action="/profile" method="post" enctype="multipart/form-data">
<input type="file" name="avatar" />
</form>
const express = require('express');
const multer = require('multer');
const upload = multer({ dest: 'uploads/' });
const app = express();
app.post('/profile', upload.single('avatar'), function (req, res, next) {
// req.file is the `avatar` file
// req.body will hold the text fields, if there were any
});
app.post('/photos/upload', upload.array('photos', 12), function (req, res, next) {
// req.files is array of `photos` files
// req.body will contain the text fields, if there were any
});
const uploadMiddleware = upload.fields([
{ name: 'avatar', maxCount: 1 },
{ name: 'gallery', maxCount: 8 },
]);
app.post('/cool-profile', uploadMiddleware, function (req, res, next) {
// req.files is an object (String -> Array) where fieldname is the key, and the value is array of files
//
// e.g.
// req.files['avatar'][0] -> File
// req.files['gallery'] -> Array
//
// req.body will contain the text fields, if there were any
});

Nel caso in cui tu abbia bisogno di gestire un modulo multipart solo testo, dovresti usare il metodo .none():

const express = require('express');
const app = express();
const multer = require('multer');
const upload = multer();
app.post('/profile', upload.none(), function (req, res, next) {
// req.body contains the text fields
});

Ecco un esempio su come multer viene utilizzato in un formato HTML. Prendi nota dei campi enctype="multipart/form-data" e name="uploaded_file":

<form action="/stats" enctype="multipart/form-data" method="post">
<div class="form-group">
<input type="file" class="form-control-file" name="uploaded_file" />
<input type="text" class="form-control" placeholder="Number of speakers" name="nspeakers" />
<input type="submit" value="Get me the stats!" class="btn btn-default" />
</div>
</form>

Poi nel file javascript si aggiungerebbero queste righe per accedere sia al file che al corpo. È importante utilizzare il valore del campo name dal modulo nella funzione di upload. Questo dice più campo sulla richiesta in cui dovrebbe cercare i file. Se questi campi non sono gli stessi nel modulo HTML e sul tuo server, il caricamento fallirà:

const multer = require('multer');
const upload = multer({ dest: './public/data/uploads/' });
app.post('/stats', upload.single('uploaded_file'), function (req, res) {
// req.file is the name of your file in the form above, here 'uploaded_file'
// req.body will hold the text fields, if there were any
console.log(req.file, req.body);
});

Complete client-side and server-side examples (browser FormData uploads of a blob and of an image) are in the examples/ folder.

API

Informazioni sul file

Ogni file contiene le seguenti informazioni:

ChiaveDescrizioneNota
fieldnameNome del campo specificato nella forma
originalnameName of the file on the user’s computer, or the full path when preservePath: true
encodingTipo di codifica del file
mimetypeTipo MIME del file
sizeDimensione del file in byte
destinazioneLa cartella in cui il file è stato salvatoDiskStorage
nomefileIl nome del file all’interno della destinazioneDiskStorage
pathIl percorso completo del file caricatoDiskStorage
bufferUn Buffer dell’intero fileMemoryStorage

multer(opts)

Multer accetta un oggetto opzioni, il più basilare di cui è la proprietà dest , che dice a Multer dove caricare i file. Nel caso in cui si ometta l’oggetto opzioni , i file saranno conservati in memoria e mai scritti su disco.

Per impostazione predefinita, Multer rinominerà i file in modo da evitare conflitti di nomi. La funzione di rinominazione può essere personalizzata in base alle tue esigenze.

Di seguito sono riportate le opzioni che possono essere passate a Multer.

ChiaveDescrizione
defCharsetDefault character set to use for text field values that do not declare one. Default: 'utf8'
defParamCharsetSet di caratteri predefinito da usare per i valori dei parametri dell’intestazione della parte (ad esempio nome file) che non sono parametri estesi (che contengono un set di caratteri esplicito). Predefinito: 'latin1'
dest o storageDove memorizzare i file
fileFilterFunzione per controllare quali file sono accettati
fileHwmhighWaterMark of each file stream (file.stream). Default: busboy’s default
highWaterMarkhighWaterMark of the multipart parser stream. Default: busboy’s default
limitsLimiti dei dati caricati
preservePathKeep the full client-supplied path in file.originalname instead of just the base name
streamHandlerFunction that feeds the request body to busboy; defaults to req.pipe(busboy)

In una media web app, potrebbe essere richiesto solo dest, e configurato come mostrato in il seguente esempio.

const upload = multer({ dest: 'uploads/' });

When preservePath is enabled, Multer passes the incoming filename through with any path segments provided by the client. This is exposed as file.originalname; it does not change the destination folder, create directories, or sanitize the path for you. file.originalname is always client-supplied and should be treated as untrusted; with preservePath it additionally contains the path segments the client sent. Normalize or validate it before using it in a custom filename or storage engine.

Se vuoi più controllo sui tuoi upload, vuoi usare l’opzione storage invece di dest. Navi multiple con motori di stoccaggio DiskStorage e MemoryStorage; Più motori sono disponibili da terze parti.

.single(fieldname)

Accetta un singolo file con il nome fieldname. Il singolo file sarà archiviato in req.file.

.array(fieldname[, maxCount])

Accetta un array di file, tutti con il nome fieldname. Opzionalmente errore se più di file maxCount vengono caricati. L’array dei file sarà memorizzato in req.files.

Files skipped by fileFilter do not count towards maxCount. Use limits.files to bound how many files are read from a request.

.fields(fields)

Accetta un mix di file, specificato da fields. Un oggetto con array di file verrà memorizzato in req.files.

fields dovrebbe essere un array di oggetti con name ed eventualmente un maxCount. Esempio:

[
{ name: 'avatar', maxCount: 1 },
{ name: 'gallery', maxCount: 8 },
];

.none()

Accetta solo campi di testo. If any file upload is made, error with code LIMIT_UNEXPECTED_FILE will be issued.

.any()

Accepts all files that come over the wire. Un array di file sarà memorizzato in req.files.

ATTENZIONE: Assicurati di gestire sempre i file caricati da un utente. Non aggiungere mai multer come middleware globale poiché un utente dannoso potrebbe caricare i file su un percorso che non ti aspettavi. Usa questa funzione solo sugli itinerari dove gestisci i file caricati.

storage

DiskStorage

Il motore di archiviazione del disco ti dà pieno controllo sulla memorizzazione dei file su disco.

const crypto = require('crypto');
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, '/tmp/my-uploads');
},
filename: function (req, file, cb) {
crypto.randomBytes(16, function (err, raw) {
if (err) return cb(err);
cb(null, file.fieldname + '-' + raw.toString('hex'));
});
},
});
const upload = multer({ storage: storage });

There are three options available: destination, filename and flush. All of them except flush are functions that determine where the file should be stored.

destination è usato per determinare in quale cartella i file caricati dovrebbero essere memorizzati. Questo può anche essere dato come una string (ad esempio '/tmp/uploads'). If no destination is given, the operating system’s default directory for temporary files is used.

Nota: Sei responsabile della creazione della directory quando fornisci come funzione destinazione . Quando si passa una stringa, multer si assicurerà che la directory viene creata per te.

filename è usato per determinare cosa il file dovrebbe essere nominato all’interno della cartella. Se non viene fornito alcun nome file, ad ogni file verrà dato un nome casuale che non include alcuna estensione del file.

Nota: Multer non aggiungerà alcuna estensione del file per te, la tua funzione dovrebbe restituire un nome file completo di estensione del file.

Ogni funzione viene superata sia la richiesta (req) che alcune informazioni su il file (file) per aiutare con la decisione.

Nota che req.body potrebbe non essere stato ancora completamente popolato. Dipende dall’ordine che il client trasmette campi e file al server.

Per capire la convenzione di chiamata utilizzata nel callback (necessità di passare null come primo parametro), fare riferimento a Node. s gestione degli errori

flush is an optional boolean. When set to true, the file data is flushed to disk with an fsync call before the upload handler runs, which prevents data loss if the process or the system crashes while the data is still sitting in the operating system’s page cache. It is disabled by default because forcing a disk flush on every upload has a performance cost. Note that this syncs the file contents only; if the new directory entry must survive a crash as well, fsync the destination directory yourself.

MemoryStorage

Il motore di memorizzazione memoria memorizza i file in memoria come oggetti Buffer. non ha alcuna opzione.

const storage = multer.memoryStorage();
const upload = multer({ storage: storage });

Quando si utilizza memoria di memoria, le informazioni del file conterranno un campo chiamato buffer che contiene l’intero file.

ATTENZIONE: Caricare file molto grandi o file relativamente piccoli in grandi numeri molto rapidamente, può causare che l’applicazione esaurisca la memoria quando viene utilizzata la memoria .

limits

Un oggetto che specifica i limiti di dimensione delle seguenti proprietà opzionali. Multer passes this object into busboy directly, and the details of the properties can be found on busboy’s page.

limits can also be a function that receives the request and returns such an object. It is called once per request, before parsing starts, so limits can depend on e.g. the authenticated user:

const upload = multer({
limits: function (req) {
return { fileSize: req.user.maxUploadSize };
},
});

Limits apply to the whole request; there is no per-file limit. To restrict individual files by type or name, use fileFilter or a custom storage engine.

Sono disponibili i seguenti valori interi:

ChiaveDescrizionePredefinito
fieldNameSizeDimensione massima nome campoInfinito
fieldSizeDimensione massima del campo (in byte)1MB
fieldsNumero massimo di campi non fileInfinito
fileSizePer forme multiple, la dimensione massima del file (in byte)Infinito
filesPer forme multiple, il numero massimo di campi di fileInfinito
partsPer forme multiple, il numero massimo di parti (campi + file)Infinito
headerPairsPer forme multiparti, il numero massimo di chiavi intestazione=>valore coppie da analizzare2000
fieldNestingDepthMax number of nesting levels for field names (e.g. a[b][c] has 2 levels)Infinito
fieldArrayIndexLimitMax numeric array index accepted inside a field name (e.g. a[3] uses index 3)Infinito

Specificare i limiti può aiutare a proteggere il vostro sito dagli attacchi di negazione del servizio (DoS).

fileFilter

Impostare questa funzione per controllare quali file devono essere caricati e quali devono essere saltati. La funzione dovrebbe apparire così:

function fileFilter(req, file, cb) {
// The function should call `cb` with a boolean
// to indicate if the file should be accepted
// To reject this file pass `false`, like so:
cb(null, false);
// To accept the file pass `true`, like so:
cb(null, true);
// You can always pass an error if something goes wrong:
cb(new Error("I don't have a clue!"));
}

streamHandler

By default Multer reads the request with req.pipe(busboy). Some platforms consume the request body before your handlers run, so there is nothing left to pipe. Google Cloud Functions and Firebase Functions, for example, expose the already-read body as req.rawBody. Provide a streamHandler to feed busboy yourself in that case:

const upload = multer({
storage: multer.memoryStorage(),
streamHandler: function (req, busboy) {
if (req.rawBody) {
busboy.end(req.rawBody);
} else {
req.pipe(busboy);
}
},
});

The function receives the request and the busboy instance and must write the whole multipart body to busboy and end it.

Security

Specifying the limits can help protect your site against denial of service (DoS) attacks. The following limits are recommended for most applications:

  • fileSize — set to the maximum expected file size for your use case
  • files — set to the maximum number of files per request
  • fields — set to the maximum number of text fields per request
  • fieldNestingDepth — set to the minimum depth your field names require (e.g. 3 for a[b][c])
  • fieldArrayIndexLimit — set to the largest array index your field names require (e.g. 100 for a[99])

Gestione errori

Quando si incontra un errore, Multer delegherà l’errore a Express. Puoi visualizzare una bella pagina di errore usando lo standard express way.

Se si desidera catturare errori specificamente da Multer, è possibile chiamare la funzione middleware da soli. Inoltre, se si desidera catturare solo gli errori Multer, puoi usare la classe MulterError che è collegata all’oggetto multer stesso (e. . err instanceof multer.MulterError).

Multer errors carry a code (e.g. LIMIT_FILE_SIZE) and, when the error concerns a specific field, its name in field. Errors about a specific file (LIMIT_FILE_SIZE, LIMIT_UNEXPECTED_FILE) also expose the client-supplied file name in filename; treat it as untrusted input, like file.originalname.

const multer = require('multer');
const upload = multer().single('avatar');
app.post('/profile', function (req, res) {
upload(req, res, function (err) {
if (err instanceof multer.MulterError) {
// A Multer error occurred when uploading.
} else if (err) {
// An unknown error occurred when uploading.
}
// Everything went fine.
});
});

Motore di stoccaggio personalizzato

Per informazioni su come costruire il proprio motore di archiviazione, vedere Multer Storage Engine.

Licenza

MIT