middleware multer

Multer es un middleware de node.js para manejar multipart/form-data, que se usa principalmente para subir archivos. Está escrito sobre busboy para máxima eficiencia.

NOTA: Multer no procesará ningún formulario que no sea multipart (multipart/form-data).

Traducciones

Este README también está disponible en otros idiomas:

Instalación

Ventana de terminal
npm install multer

Uso

Multer añade un objeto body y un objeto file o files al objeto de petición. El objeto body contiene los valores de los campos de texto del formulario, el objeto file o files contiene los archivos subidos a través del formulario.

Ejemplo de uso básico:

No olvides el enctype="multipart/form-data" en tu formulario.

<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
});

En caso de que necesites manejar un formulario multipart solo de texto, debes usar el método .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
});

Aquí hay un ejemplo de cómo se usa multer en un formulario HTML. Presta especial atención a los campos enctype="multipart/form-data" y 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>

Luego en tu archivo javascript añadirías estas líneas para acceder tanto al archivo como al body. Es importante que uses el valor del campo name del formulario en tu función de subida. Esto le indica a multer en qué campo de la petición debe buscar los archivos. Si estos campos no son los mismos en el formulario HTML y en tu servidor, tu subida fallará:

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);
});

API

Información del archivo

Cada archivo contiene la siguiente información:

ClaveDescripciónNota
fieldnameNombre del campo especificado en el formulario
originalnameNombre del archivo en la computadora del usuario
encodingTipo de codificación del archivo
mimetypeTipo MIME del archivo
sizeTamaño del archivo en bytes
destinationLa carpeta donde se ha guardado el archivoDiskStorage
filenameEl nombre del archivo dentro de destinationDiskStorage
pathLa ruta completa al archivo subidoDiskStorage
bufferUn Buffer del archivo completoMemoryStorage

multer(opts)

Multer acepta un objeto de opciones, el más básico de los cuales es la propiedad dest, que indica a Multer dónde subir los archivos. Si omites el objeto de opciones, los archivos se mantendrán en memoria y nunca se escribirán en disco.

Por defecto, Multer renombrará los archivos para evitar conflictos de nombres. La función de renombrado puede personalizarse según tus necesidades.

Las siguientes son las opciones que se pueden pasar a Multer.

ClaveDescripción
dest o storageDónde almacenar los archivos
fileFilterFunción para controlar qué archivos se aceptan
limitsLímites de los datos subidos
preservePathMantener la ruta completa de los archivos en lugar de solo el nombre base
defParamCharsetConjunto de caracteres por defecto a usar para valores de parámetros de encabezado de parte (ej. filename) que no son parámetros extendidos (que contienen un charset explícito). Por defecto: 'latin1'

En una aplicación web promedio, solo dest podría ser necesario, y configurarse como se muestra en el siguiente ejemplo.

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

Si quieres más control sobre tus subidas, querrás usar la opción storage en lugar de dest. Multer incluye motores de almacenamiento DiskStorage y MemoryStorage; hay más motores disponibles de terceros.

.single(fieldname)

Acepta un solo archivo con el nombre fieldname. El archivo único se almacenará en req.file.

.array(fieldname[, maxCount])

Acepta un array de archivos, todos con el nombre fieldname. Opcionalmente lanza un error si se suben más de maxCount archivos. El array de archivos se almacenará en req.files.

.fields(fields)

Acepta una mezcla de archivos, especificados por fields. Un objeto con arrays de archivos se almacenará en req.files.

fields debe ser un array de objetos con name y opcionalmente un maxCount. Ejemplo:

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

.none()

Acepta solo campos de texto. Si se hace cualquier subida de archivo, se emitirá un error con código “LIMIT_UNEXPECTED_FILE”.

.any()

Acepta todos los archivos que llegan. Un array de archivos se almacenará en req.files.

ADVERTENCIA: Asegúrate de siempre manejar los archivos que un usuario sube. Nunca añadas multer como middleware global ya que un usuario malintencionado podría subir archivos a una ruta que no anticipaste. Usa esta función solo en rutas donde estés manejando los archivos subidos.

storage

DiskStorage

El motor de almacenamiento en disco te da control total sobre el almacenamiento de archivos en disco.

const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, '/tmp/my-uploads');
},
filename: function (req, file, cb) {
const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1e9);
cb(null, file.fieldname + '-' + uniqueSuffix);
},
});
const upload = multer({ storage: storage });

Hay dos opciones disponibles, destination y filename. Ambas son funciones que determinan dónde se debe almacenar el archivo.

destination se usa para determinar en qué carpeta se deben almacenar los archivos subidos. Esto también puede darse como string (ej. '/tmp/uploads'). Si no se dá destination, se usa el directorio por defecto del sistema operativo para archivos temporales.

Nota: Tú eres responsable de crear el directorio al proporcionar destination como función. Al pasar una cadena, multer se asegurará de que el directorio se cree por ti.

filename se usa para determinar cómo se debe nombrar el archivo dentro de la carpeta. Si no se dá filename, cada archivo recibirá un nombre aleatorio que no incluye ninguna extensión de archivo.

Nota: Multer no añadirá ninguna extensión de archivo por ti, tu función debe devolver un nombre de archivo completo con extensión de archivo.

Cada función recibe tanto la petición (req) como información sobre el archivo (file) para ayudar en la decisión.

Ten en cuenta que req.body podría no haberse poblado completamente aún. Depende del orden en que el cliente transmite campos y archivos al servidor.

Para entender la convención de llamada usada en el callback (necesidad de pasar null como primer parámetro), consulta manejo de errores de Node.js

MemoryStorage

El motor de almacenamiento en memoria guarda los archivos en memoria como objetos Buffer. No tiene ninguna opción.

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

Cuando se usa almacenamiento en memoria, la información del archivo contendrá un campo llamado buffer que contiene el archivo completo.

ADVERTENCIA: Subir archivos muy grandes, o archivos relativamente pequeños en grandes cantidades muy rápidamente, puede causar que tu aplicación se quede sin memoria cuando se usa almacenamiento en memoria.

limits

Un objeto que especifica los límites de tamaño de las siguientes propiedades opcionales. Multer pasa este objeto a busboy directamente, y los detalles de las propiedades pueden encontrarse en la página de busboy.

Los siguientes valores enteros están disponibles:

ClaveDescripciónPor defecto
fieldNameSizeTamaño máximo del nombre de campo100 bytes
fieldSizeTamaño máximo del valor de campo (en bytes)1MB
fieldsNúmero máximo de campos que no son archivosInfinito
fileSizePara formularios multipart, el tamaño máximo de archivo (en bytes)Infinito
filesPara formularios multipart, el número máximo de campos de archivoInfinito
partsPara formularios multipart, el número máximo de partes (campos + archivos)Infinito
headerPairsPara formularios multipart, el número máximo de pares clave=>valor de encabezado a analizar2000
fieldNestingDepthNúmero máximo de niveles de anidamiento para nombres de campo (ej. a[b][c] tiene 2 niveles)Infinito

Especificar los límites puede ayudar a proteger tu sitio contra ataques de denegación de servicio (DoS).

fileFilter

Establece esto como una función para controlar qué archivos deben subirse y cuáles deben omitirse. La función debería verse así:

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!"));
}

Seguridad

Especificar los limits puede ayudar a proteger tu sitio contra ataques de denegación de servicio (DoS). Los siguientes límites son recomendados para la mayoría de las aplicaciones:

  • fileSize — establece el tamaño máximo esperado de archivo para tu caso de uso
  • files — establece el número máximo de archivos por petición
  • fields — establece el número máximo de campos de texto por petición
  • fieldNestingDepth — establece la profundidad mínima que requieren tus nombres de campo (ej. 3 para a[b][c])

Manejo de errores

Al encontrar un error, Multer delegará el error a Express. Puedes mostrar una página de error agradable usando la forma estándar de express.

Si quieres capturar errores específicamente de Multer, puedes llamar la función de middleware por ti mismo. Además, si quieres capturar solo los errores de Multer, puedes usar la clase MulterError que está adjunta al objeto multer mismo (ej. err instanceof multer.MulterError).

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.
});
});

Motor de almacenamiento personalizado

Para información sobre cómo construir tu propio motor de almacenamiento, consulta Motor de almacenamiento de Multer.

Licencia

MIT