1.12 formidable

formidable 在 Node.js 和 Express 中的使用详解

formidable 是一个轻量级的 Node.js 模块,专门用于解析 multipart/form-data 格式的表单(包括文件上传):

一、在原生 Node.js 中使用

npm install formidable
2. 基础示例
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'); });

二、在 Express 中使用

1. 基础集成
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'); });
2. 封装为中间件(推荐)
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);

三、高级功能

1. 事件监听(进度、文件等)
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) => {
  // ...
});
2. 文件过滤和验证
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: '服务器错误' });
  }
  // ...
});
3. 处理多个文件
// 多文件上传(字段名相同)
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 });
  });
});

注意事项

  1. 安全问题

    • 始终验证文件类型(通过扩展名和魔数)。
    • 重命名上传的文件,避免路径注入攻击。
    • 设置合理的文件大小限制。
  2. 性能优化

    • 对于大文件 ,上传到云存储(如 AWS S3),减少服务器负载

总结

  • 适用场景formidable 适合需要细粒度控制上传过程(如进度监听)或轻量级项目。
  • 推荐配置
    const form = formidable({
      uploadDir: './uploads',
      keepExtensions: true,
      maxFileSize: 10 * 1024 * 1024, // 10MB
      filter: (part) => part.mimetype && part.mimetype.includes('image')
    });
    
  • 生产环境:考虑结合云存储(如 AWS S3、阿里云 OSS)和 CDN 优化性能。

你可能感兴趣的:(vue3,#,nodejs,node.js)