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:
| العربية | Arabic |
| 简体中文 | Chinese |
| Français | French |
| 한국어 | Korean |
| Português | Portuguese (BR) |
| Русский язык | Russian |
| Español | Spanish |
| O’zbek tili | Uzbek |
| Việt Nam | Vietnamese |
| Türkçe | Turkish |
Instalación
npm install multeryarn add multerpnpm add multerbun add multerUso
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:
| Clave | Descripción | Nota |
|---|---|---|
fieldname | Nombre del campo especificado en el formulario | |
originalname | Nombre del archivo en la computadora del usuario | |
encoding | Tipo de codificación del archivo | |
mimetype | Tipo MIME del archivo | |
size | Tamaño del archivo en bytes | |
destination | La carpeta donde se ha guardado el archivo | DiskStorage |
filename | El nombre del archivo dentro de destination | DiskStorage |
path | La ruta completa al archivo subido | DiskStorage |
buffer | Un Buffer del archivo completo | MemoryStorage |
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.
| Clave | Descripción |
|---|---|
dest o storage | Dónde almacenar los archivos |
fileFilter | Función para controlar qué archivos se aceptan |
limits | Límites de los datos subidos |
preservePath | Mantener la ruta completa de los archivos en lugar de solo el nombre base |
defParamCharset | Conjunto 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:
| Clave | Descripción | Por defecto |
|---|---|---|
fieldNameSize | Tamaño máximo del nombre de campo | 100 bytes |
fieldSize | Tamaño máximo del valor de campo (en bytes) | 1MB |
fields | Número máximo de campos que no son archivos | Infinito |
fileSize | Para formularios multipart, el tamaño máximo de archivo (en bytes) | Infinito |
files | Para formularios multipart, el número máximo de campos de archivo | Infinito |
parts | Para formularios multipart, el número máximo de partes (campos + archivos) | Infinito |
headerPairs | Para formularios multipart, el número máximo de pares clave=>valor de encabezado a analizar | 2000 |
fieldNestingDepth | Nú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 usofiles— establece el número máximo de archivos por peticiónfields— establece el número máximo de campos de texto por peticiónfieldNestingDepth— establece la profundidad mínima que requieren tus nombres de campo (ej.3paraa[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.