A Node.js module for parsing form data, especially file uploads.
If you have any how-to kind of questions, please read the ContributingGuide and Code of Conductdocuments.
For bugs reports and feature requests, please create anissue or ping @tunnckoCoreat Twitter.
This project is semantically versioned and available aspart of the Tidelift Subscription for professional gradeassurances, enhanced support and security.Learn more.
The maintainers of formidable
and thousands of other packages are workingwith Tidelift to deliver commercial support and maintenance for the Open Sourcedependencies you use to build your applications. Save time, reduce risk, andimprove code health, while paying the maintainers of the exact dependencies youuse.
This module was initially developed by@felixge forTransloadit, a service focused on uploading andencoding images and videos. It has been battle-tested against hundreds of GBs offile uploads from a large variety of clients and is considered production-readyand is used in production for years.
Currently, we are few maintainers trying to deal with it. :) More contributorsare always welcome!
Note: The github master
branch is a "canary" branch - try it withnpm i formidable@canary
. Do not expect (for now) things from it to be insidethelatest
"dist-tag" in the Npm. Theformidable@latest
is thev1.2.1
versionand probably it will be the lastv1
release!
Note: v2 is coming soon!
options.fileWriteStreamHandler
)This project requires Node.js >= 10.13
. Install it usingyarn or npm.
We highlyrecommend to use Yarn when you think to contribute to this project.
npm install formidable
# or the canary version
npm install formidable@canary
or with Yarn v1/v2
yarn add formidable
# or the canary version
yarn add formidable@canary
This is a low-level package, and if you're using a high-level framework it mayalready be included. Check the examples below and the examples/
folder.
For more examples look at the examples/
directory.
Parse an incoming file upload, with theNode.js's built-in http
module.
const http = require('http');
const formidable = require('formidable');
const server = http.createServer((req, res) => {
if (req.url === '/api/upload' && req.method.toLowerCase() === 'post') {
// parse a file upload
const form = formidable({ multiples: true });
form.parse(req, (err, fields, files) => {
if (err) {
res.writeHead(err.httpCode || 400, { 'Content-Type': 'text/plain' });
res.end(String(err));
return;
}
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ fields, files }, null, 2));
});
return;
}
// show a file upload form
res.writeHead(200, { 'Content-Type': 'text/html' });
res.end(`
<h2>With Node.js <code>"http"</code> module</h2>
<form action="/api/upload" enctype="multipart/form-data" method="post">
<div>Text field title: <input type="text" name="title" /></div>
<div>File: <input type="file" name="multipleFiles" multiple="multiple" /></div>
<input type="submit" value="Upload" />
</form>
`);
});
server.listen(8080, () => {
console.log('Server listening on http://localhost:8080/ ...');
});
There are multiple variants to do this, but Formidable just need Node.js Requeststream, so something like the following example should work just fine, withoutany third-party Express.js middleware.
Or try theexamples/with-express.js
const express = require('express');
const formidable = require('formidable');
const app = express();
app.get('/', (req, res) => {
res.send(`
<h2>With <code>"express"</code> npm package</h2>
<form action="/api/upload" enctype="multipart/form-data" method="post">
<div>Text field title: <input type="text" name="title" /></div>
<div>File: <input type="file" name="someExpressFiles" multiple="multiple" /></div>
<input type="submit" value="Upload" />
</form>
`);
});
app.post('/api/upload', (req, res, next) => {
const form = formidable({ multiples: true });
form.parse(req, (err, fields, files) => {
if (err) {
next(err);
return;
}
res.json({ fields, files });
});
});
app.listen(3000, () => {
console.log('Server listening on http://localhost:3000 ...');
});
Of course, with Koa v1, v2 or future v3 the thingsare very similar. You can use formidable
manually as shown below or throughthe koa-better-body package which isusing formidable
under the hood and support more features and differentrequest bodies, check its documentation for more info.
Note: this example is assuming Koa v2. Be aware that you should pass ctx.req
which is Node.js's Request, and NOT the ctx.request
which is Koa's Requestobject - there is a difference.
const Koa = require('koa');
const formidable = require('formidable');
const app = new Koa();
app.on('error', (err) => {
console.error('server error', err);
});
app.use(async (ctx, next) => {
if (ctx.url === '/api/upload' && ctx.method.toLowerCase() === 'post') {
const form = formidable({ multiples: true });
// not very elegant, but that's for now if you don't want to use `koa-better-body`
// or other middlewares.
await new Promise((resolve, reject) => {
form.parse(ctx.req, (err, fields, files) => {
if (err) {
reject(err);
return;
}
ctx.set('Content-Type', 'application/json');
ctx.status = 200;
ctx.state = { fields, files };
ctx.body = JSON.stringify(ctx.state, null, 2);
resolve();
});
});
await next();
return;
}
// show a file upload form
ctx.set('Content-Type', 'text/html');
ctx.status = 200;
ctx.body = `
<h2>With <code>"koa"</code> npm package</h2>
<form action="/api/upload" enctype="multipart/form-data" method="post">
<div>Text field title: <input type="text" name="title" /></div>
<div>File: <input type="file" name="koaFiles" multiple="multiple" /></div>
<input type="submit" value="Upload" />
</form>
`;
});
app.use((ctx) => {
console.log('The next middleware is called');
console.log('Results:', ctx.state);
});
app.listen(3000, () => {
console.log('Server listening on http://localhost:3000 ...');
});
The benchmark is quite old, from the old codebase. But maybe quite true though.Previously the numbers was around ~500 mb/sec. Currently with moving to the newNode.js Streams API it's faster. You can clearly see the differences between theNode versions.
Note: a lot better benchmarking could and should be done in future.
Benchmarked on 8GB RAM, Xeon X3440 (2.53 GHz, 4 cores, 8 threads)
~/github/node-formidable master
❯ nve --parallel 8 10 12 13 node benchmark/bench-multipart-parser.js
⬢ Node 8
1261.08 mb/sec
⬢ Node 10
1113.04 mb/sec
⬢ Node 12
2107.00 mb/sec
⬢ Node 13
2566.42 mb/sec
All shown are equivalent.
Please pass options
to the function/constructor, not by assigningthem to the instance form
const formidable = require('formidable');
const form = formidable(options);
// or
const { formidable } = require('formidable');
const form = formidable(options);
// or
const { IncomingForm } = require('formidable');
const form = new IncomingForm(options);
// or
const { Formidable } = require('formidable');
const form = new Formidable(options);
See it's defaults in src/Formidable.js DEFAULT_OPTIONS(the DEFAULT_OPTIONS
constant).
options.encoding
{string} - default 'utf-8'
; sets encoding forincoming form fields,
options.uploadDir
{string} - default os.tmpdir()
; the directory forplacing file uploads in. You can move them later by using fs.rename()
.
options.keepExtensions
{boolean} - default false
; to include theextensions of the original files or not
options.allowEmptyFiles
{boolean} - default true
; allow upload emptyfiles
options.minFileSize
{number} - default 1
(1byte); the minium size ofuploaded file.
options.maxFileSize
{number} - default 200 * 1024 * 1024
(200mb);limit the size of uploaded file.
options.maxFields
{number} - default 1000
; limit the number of fields, set 0 for unlimited
options.maxFieldsSize
{number} - default 20 * 1024 * 1024
(20mb);limit the amount of memory all fields together (except files) can allocate inbytes.
options.hashAlgorithm
{string | false} - default false
; include checksums calculatedfor incoming files, set this to some hash algorithm, seecrypto.createHashfor available algorithms
options.fileWriteStreamHandler
{function} - default null
, which bydefault writes to host machine file system every file parsed; The functionshould return an instance of aWritable streamthat will receive the uploaded file data. With this option, you can have anycustom behavior regarding where the uploaded file data will be streamed for.If you are looking to write the file uploaded in other types of cloud storages(AWS S3, Azure blob storage, Google cloud storage) or private file storage,this is the option you're looking for. When this option is defined the defaultbehavior of writing the file in the host machine file system is lost.
options.multiples
{boolean} - default false
; when you call the.parse
method, the files
argument (of the callback) will contain arrays offiles for inputs which submit multiple files using the HTML5 multiple
attribute. Also, the fields
argument will contain arrays of values forfields that have names ending with '[]'.
options.filename
{function} - default undefined
Use it to controlnewFilename. Must return a string. Will be joined with options.uploadDir.
options.filter
{function} - default function that always returns true.Use it to filter files before they are uploaded. Must return a boolean.
options.filename
{function} function (name, ext, part, form) -> stringNote: If this size of combined fields, or size of some file is exceeded, an'error'
event is fired.
// The amount of bytes received for this form so far.
form.bytesReceived;
// The expected number of bytes in this form.
form.bytesExpected;
options.filter
{function} function ({name, originalFilename, mimetype}) -> booleanNote: use an outside variable to cancel all uploads upon the first error
const options = {
filter: function ({name, originalFilename, mimetype}) {
// keep only images
return mimetype && mimetype.includes("image");
}
};
Parses an incoming Node.js request
containing form data. If callback
isprovided, all fields and files are collected and passed to the callback.
const formidable = require('formidable');
const form = formidable({ multiples: true, uploadDir: __dirname });
form.parse(req, (err, fields, files) => {
console.log('fields:', fields);
console.log('files:', files);
});
You may overwrite this method if you are interested in directly accessing themultipart stream. Doing so will disable any 'field'
/ 'file'
eventsprocessing which would occur otherwise, making you fully responsible forhandling the processing.
About uploadDir
, given the following directory structure
project-name
├── src
│ └── server.js
│
└── uploads
└── image.jpg
__dirname
would be the same directory as the source file itself (src)
`${__dirname}/../uploads`
to put files in uploads.
Omitting __dirname
would make the path relative to the current working directory. This would be the same if server.js is launched from src but not project-name.
null
will use default which is os.tmpdir()
Note: If the directory does not exist, the uploaded files are silently discarded. To make sure it exists:
import {createNecessaryDirectoriesSync} from "filesac";
const uploadPath = `${__dirname}/../uploads`;
createNecessaryDirectoriesSync(`${uploadPath}/x`);
In the example below, we listen on couple of events and direct them to thedata
listener, so you can do whatever you choose there, based on whether itsbefore the file been emitted, the header value, the header name, on field, onfile and etc.
Or the other way could be to just override the form.onPart
as it's shown a bitlater.
form.once('error', console.error);
form.on('fileBegin', (formname, file) => {
form.emit('data', { name: 'fileBegin', formname, value: file });
});
form.on('file', (formname, file) => {
form.emit('data', { name: 'file', formname, value: file });
});
form.on('field', (fieldName, fieldValue) => {
form.emit('data', { name: 'field', key: fieldName, value: fieldValue });
});
form.once('end', () => {
console.log('Done!');
});
// If you want to customize whatever you want...
form.on('data', ({ name, key, value, buffer, start, end, formname, ...more }) => {
if (name === 'partBegin') {
}
if (name === 'partData') {
}
if (name === 'headerField') {
}
if (name === 'headerValue') {
}
if (name === 'headerEnd') {
}
if (name === 'headersEnd') {
}
if (name === 'field') {
console.log('field name:', key);
console.log('field value:', value);
}
if (name === 'file') {
console.log('file:', formname, value);
}
if (name === 'fileBegin') {
console.log('fileBegin:', formname, value);
}
});
A method that allows you to extend the Formidable library. By default we include4 plugins, which esentially are adapters to plug the different built-in parsers.
The plugins added by this method are always enabled.
See src/plugins/ for more detailed look on default plugins.
The plugin
param has such signature:
function(formidable: Formidable, options: Options): void;
The architecture is simple. The plugin
is a function that is passed with theFormidable instance (the form
across the README examples) and the options.
Note: the plugin function's this
context is also the same instance.
const formidable = require('formidable');
const form = formidable({ keepExtensions: true });
form.use((self, options) => {
// self === this === form
console.log('woohoo, custom plugin');
// do your stuff; check `src/plugins` for inspiration
});
form.parse(req, (error, fields, files) => {
console.log('done!');
});
Important to note, is that inside plugin this.options
, self.options
andoptions
MAY or MAY NOT be the same. General best practice is to always use thethis
, so you can later test your plugin independently and more easily.
If you want to disable some parsing capabilities of Formidable, you can disablethe plugin which corresponds to the parser. For example, if you want to disablemultipart parsing (so the src/parsers/Multipart.jswhich is used in src/plugins/multipart.js), thenyou can remove it from the options.enabledPlugins
, like so
const { Formidable } = require('formidable');
const form = new Formidable({
hashAlgorithm: 'sha1',
enabledPlugins: ['octetstream', 'querystring', 'json'],
});
Be aware that the order MAY be important too. The names corresponds 1:1 tofiles in src/plugins/ folder.
Pull requests for new built-in plugins MAY be accepted - for example, moreadvanced querystring parser. Add your plugin as a new file in src/plugins/
folder (lowercased) and follow how the other plugins are made.
If you want to use Formidable to only handle certain parts for you, you can dosomething similar. Or see#387 forinspiration, you can for example validate the mime-type.
const form = formidable();
form.onPart = (part) => {
part.on('data', (buffer) => {
// do whatever you want here
});
};
For example, force Formidable to be used only on non-file "parts" (i.e., htmlfields)
const form = formidable();
form.onPart = function (part) {
// let formidable handle only non-file parts
if (part.originalFilename === '' || !part.mimetype) {
// used internally, please do not override!
form._handlePart(part);
}
};
export interface File {
// The size of the uploaded file in bytes.
// If the file is still being uploaded (see `'fileBegin'` event),
// this property says how many bytes of the file have been written to disk yet.
file.size: number;
// The path this file is being written to. You can modify this in the `'fileBegin'` event in
// case you are unhappy with the way formidable generates a temporary path for your files.
file.filepath: string;
// The name this file had according to the uploading client.
file.originalFilename: string | null;
// calculated based on options provided
file.newFilename: string | null;
// The mime type of this file, according to the uploading client.
file.mimetype: string | null;
// A Date object (or `null`) containing the time this file was last written to.
// Mostly here for compatibility with the [W3C File API Draft](http://dev.w3.org/2006/webapi/FileAPI/).
file.mtime: Date | null;
file.hashAlgorithm: false | |'sha1' | 'md5' | 'sha256'
// If `options.hashAlgorithm` calculation was set, you can read the hex digest out of this var (at the end it will be a string)
file.hash: string | object | null;
}
This method returns a JSON-representation of the file, allowing you toJSON.stringify()
the file which is useful for logging and responding torequests.
'progress'
Emitted after each incoming chunk of data that has been parsed. Can be used toroll your own progress bar.
form.on('progress', (bytesReceived, bytesExpected) => {});
'field'
Emitted whenever a field / value pair has been received.
form.on('field', (name, value) => {});
'fileBegin'
Emitted whenever a new file is detected in the upload stream. Use this event ifyou want to stream the file to somewhere else while buffering the upload on thefile system.
form.on('fileBegin', (formName, file) => {
// accessible here
// formName the name in the form (<input name="thisname" type="file">) or http filename for octetstream
// file.originalFilename http filename or null if there was a parsing error
// file.newFilename generated hexoid or what options.filename returned
// file.filepath default pathnme as per options.uploadDir and options.filename
// file.filepath = CUSTOM_PATH // to change the final path
});
'file'
Emitted whenever a field / file pair has been received. file
is an instance ofFile
.
form.on('file', (formname, file) => {
// same as fileBegin, except
// it is too late to change file.filepath
// file.hash is available if options.hash was used
});
'error'
Emitted when there is an error processing the incoming form. A request thatexperiences an error is automatically paused, you will have to manually callrequest.resume()
if you want the request to continue firing 'data'
events.
May have error.httpCode
and error.code
attached.
form.on('error', (err) => {});
'aborted'
Emitted when the request was aborted by the user. Right now this can be due to a'timeout' or 'close' event on the socket. After this event is emitted, anerror
event will follow. In the future there will be a separate 'timeout'event (needs a change in the node core).
form.on('aborted', () => {});
'end'
Emitted when the entire request has been received, and all contained files havefinished flushing to disk. This is a great place for you to send your response.
form.on('end', () => {});
multipart_parser.js
.If the documentation is unclear or has a typo, please click on the page's Edit
button (pencil icon) and suggest a correction. If you would like to help us fixa bug or add a new feature, please check our ContributingGuide. Pull requests are welcome!
Thanks goes to these wonderful people(emoji key):
From a Felix blog post:
Formidable is licensed under the MIT License.
formidable模块是一个Node.js模块,主要用于解析表单,支持get post请求参数,文件上传等。 下载 formidable 模块 可以通过 npm 下载,模块的引入还是用通过 require 。 npm i formidable 创建解析对象 创建解析对象有四种方式,每种方式都可以使用并且没有区别 const formidable = require('formidable');
formidable模块实现了上传和编码图片和视频。它支持GB级上传数据处理,支持多种客户端数据提交。有极高的测试覆盖率,非常适合在生产环境中使用。 安装方法 这是一个低版本的包,如果在开发中使用高版本的框架(如Express),formidable模块已经包含在框架中。具体用法参考:讨论。 通过npm安装: npm install formidable@latest formidable模块的
文件下载 文件下载,可以利用 Express 内置的 express.static 托管静态文件,例如图片、CSS、JavaScript 文件等1 app.use(express.static('public')); 这样就可以访问 public 目录下的资源了1 http://localhost:3000/images/bg.png 如果资源文件放在多个目录,则可以多次调用 express.st
今天总结了下Node.js的Formidable模块的使用,下面做一些简要的说明。 创建Formidable.IncomingForm对象 var form = new formidable.IncomingForm() form.encoding = 'utf-8' 设置表单域的编码 form.uploadDir = "/my/dir"; 设置上传文件存放的文件夹,默认为系统的临时文件夹,可
#环境 windows10 1.请检查自己的下载路径node_modules文件中是否包含’formidable’等文件夹。 (下载’formidable’模块时没有全局下载该模块,我习惯直接打开cmd然后输入node命令,这导致我在下载模块的时候直接进行了非全局下载,即下载到了C:\WINDOWS\system32文件夹中。使用卸载命令移除该模块和其.json文件) npm uninstall
版本信息:2.0.1 一、作用 作用:解析表单,支持get请求参数,post请求参数、文件上传。 二、使用步骤 // 引入formidable第三方模块 const formidable = require("formidable"); // 1.创建表单解析对象 // 3.保留上传文件的后缀 const form = formidable({ keepExtensions: true }); /
本文介绍formidable模块:保留上传的文件的扩展名问题 当前下载的版本为 "formidable": "^2.0.1" 结合FormData对象的使用 前端代码: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content=
1.下载包 npm i formidable 2.传入形式 传递options给函数/构造函数,而不要将其分配给实例form 四种任选一种即可 const formidable = require('formidable'); const form = formidable(options); // or const { formidable } = require('formidable')
var express = require('express') var router = express.Router() const { IncomingForm } = require('formidable') const fs = require('fs') router.post('/', function (req, res, next) { // 文件上传操作的配置项 le