formidable
是一个轻量级的 Node.js 模块,专门用于解析 multipart/form-data
格式的表单(包括文件上传):
npm install formidable
const http = require('http');
const formidable = require('formidable');
const fs = require('fs');
const path = require('path');
const server = http.createServer((req, res) => {
if (req.method === 'POST') {
// 创建 formidable 实例
const form = formidable({
multiples: true, // 允许多文件上传
uploadDir: path.join(__dirname, 'uploads'), // 上传目录
keepExtensions: true // 保留文件扩展名
});
// 解析表单
form.parse(req, (err, fields, files) => {
if (err) {
console.error('解析表单错误:', err);
res.statusCode = 500;
res.end('服务器错误');
return;
}
console.log('文本字段:', fields);
console.log('上传的文件:', files);
// 如果是单文件上传,files.file 是单个文件对象
if (files.file) {
const file = Array.isArray(files.file) ? files.file[0] : files.file;
console.log(`上传的文件: ${file.originalFilename}, 保存为: ${file.filepath}`);
}
res.end('上传完成');
});
} else {
// 返回上传表单
//设置为utf-8编码
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
res.end(`
`);
}
});
// 创建上传目录
fs.mkdirSync(path.join(__dirname, 'uploads'), { recursive: true });
server.listen(3000, () => {
console.log('服务器运行在 http://localhost:3000');
});
const express = require('express');
const formidable = require('formidable');
const path = require('path');
const fs = require('fs');
const app = express();
const uploadDir = path.join(__dirname, 'uploads');
// 创建上传目录
fs.mkdirSync(uploadDir, { recursive: true });
// 处理文件上传
app.post('/upload', (req, res) => {
const form = formidable({
uploadDir,
keepExtensions: true
});
form.parse(req, (err, fields, files) => {
if (err) {
console.error('解析表单错误:', err);
return res.status(500).json({ error: '服务器错误' });
}
// 重命名文件(可选)
if (files.file) {
const file = Array.isArray(files.file) ? files.file[0] : files.file;
const newPath = path.join(uploadDir, `${Date.now()}_${file.originalFilename}`);
fs.rename(file.filepath, newPath, (err) => {
if (err) {
console.error('重命名文件错误:', err);
return res.status(500).json({ error: '保存文件失败' });
}
});
}
res.json({
success: true,
fields,
files
});
});
});
// 提供上传表单
app.get('/', (req, res) => {
res.send(`
`);
});
app.listen(3000, () => {
console.log('服务器运行在 http://localhost:3000');
});
const express = require('express');
const formidable = require('formidable');
const app = express();
// 自定义 formidable 中间件
const formidableMiddleware = (options = {}) => {
return (req, res, next) => {
const form = formidable(options);
form.parse(req, (err, fields, files) => {
if (err) {
return next(err);
}
// 将解析后的字段和文件挂载到 req 对象
req.fields = fields;
req.files = files;
next();
});
};
};
// 使用中间件
app.post('/upload', formidableMiddleware({
uploadDir: './uploads',
keepExtensions: true
}), (req, res) => {
res.json({
success: true,
fields: req.fields,
files: req.files
});
});
app.listen(3000);
const form = formidable({ uploadDir: './uploads' });
// 监听文件开始上传事件
form.on('fileBegin', (name, file) => {
console.log(`开始上传文件: ${file.originalFilename}`);
});
// 监听文件上传事件
form.on('file', (name, file) => {
console.log(`文件上传完成: ${file.originalFilename}`);
});
// 监听进度事件(用于显示上传进度)
form.on('progress', (bytesReceived, bytesExpected) => {
const percent = Math.round((bytesReceived / bytesExpected) * 100);
console.log(`上传进度: ${percent}%`);
});
form.parse(req, (err, fields, files) => {
// ...
});
const form = formidable({
uploadDir: './uploads',
filter: (part) => {
// 只允许上传图片
return part.mimetype && part.mimetype.includes('image');
},
maxFileSize: 10 * 1024 * 1024, // 10MB 限制
});
form.parse(req, (err, fields, files) => {
if (err) {
if (err.code === 'LIMIT_FILE_SIZE') {
return res.status(413).json({ error: '文件过大' });
}
return res.status(500).json({ error: '服务器错误' });
}
// ...
});
// 多文件上传(字段名相同)
app.post('/upload-multiple', (req, res) => {
const form = formidable({ uploadDir: './uploads' });
form.parse(req, (err, fields, files) => {
if (err) return res.status(500).json({ error: '服务器错误' });
// files.file 是数组(如果上传多个文件)
if (Array.isArray(files.file)) {
files.file.forEach(file => {
console.log(`上传的文件: ${file.originalFilename}`);
});
} else {
console.log(`上传的文件: ${files.file.originalFilename}`);
}
res.json({ success: true });
});
});
安全问题:
性能优化:
formidable
适合需要细粒度控制上传过程(如进度监听)或轻量级项目。const form = formidable({
uploadDir: './uploads',
keepExtensions: true,
maxFileSize: 10 * 1024 * 1024, // 10MB
filter: (part) => part.mimetype && part.mimetype.includes('image')
});