Nodejs express formidable(不使用body-parser) 多文件上传 请教

Nodejs express formidable(不使用body-parser) 多文件上传 请教

由于新版本的express 使用:app.use(express.json());app.use(express.urlencoded());app.use(require(‘connect-multiparty’)()); //(connect-multiparty需要另外安装) 来代替app.use(express.bodyParser()); 那么我想着如何在不使用app.use(express.bodyParser({ keepExtensions: true, uploadDir: ‘./public/images’ }));的情况下,使用formidable来实现多文件上传呢?

问题来了看代码(代码是照着那个博客代码写的): app.js app.use(express.json()); app.use(express.urlencoded()); //app.use(express.multipart()); app.use(require(‘connect-multiparty’)()); //app.js中其他代码未列出 和 博客实例app.js代码是相同的。

upload.ejs:

  <%- include header %>
    <form method='post' action='/upload' enctype='multipart/form-data' >
         <input type="file" name='file1'/><br>
        <input type="file" name='file2'/><br>
        <input type="file" name='file3'/><br>
        <input type="file" name='file4'/><br>
        <input type="file" name='file5'/><br>
        <input type="submit" />
    </form>
  <%- include footer %>

index.js: 路由处理部分

var crypto = require('crypto'),   //可用其生成散列值来加密
fs = require('fs'),
User = require('../models/user.js');
var Post = require('../models/post.js');
var formidable = require('formidable');

app.post(’/upload’, function(req, res){

var form = new formidable.IncomingForm();

form.uploadDir = './public/images/';    //上传目录
form.keepExtensions = true;             //保留后缀格式
form.maxFieldsSize = 2*1024*1024;       //文件大小
console.log('new formidable',form);
return res.redirect('/');              //这是为了测试
form.parse(req, function(err, fields, files){

    /*if (err){
     req.flash('error', '文件上传失败');
     return res.redirect('/upload');
     }*/

    //console.log('formidable fields:', fields);
    /* for (var i in files){
     if (files[i].size == 0){
     //使用同步方式删除一个文件
     fs.unlinkSync(files[i].path);
     console.log('file path:',files[i].path);
     console.log('success remove a empty file');
     }else{
     var target_path = './public/images/' + files[i].name;  //这里重名时  一定要注意
     //使用同步方式重命名一个文件
     fs.renameSync(files[i].path, target_path);
     console.log('successfully rename a file');
     }
     }*/
   // req.flash('success', '文件上传成功!');
    //res.redirect('/upload');

});

问题:如果没有在 form.parse()前使用return 那么点击上传时, 页面会一直显示正在加载,估计是异步哪里的问题。 接下来我用app.post(’/upload’, function(req, res){ console.log(‘new formidable’,form); return res.redirect(’/’); } 这个测试 ,文件可以上传,并且打印出的信息:

  new formidable { domain: null,

_events: {},

_maxListeners: 10, error: null, ended: false, maxFields: 1000, maxFieldsSize: 2097152, keepExtensions: false, uploadDir: ‘C:\Users\ADMINI~1\AppData\Local\Temp’, //看这里 encoding: ‘utf-8’, headers: null, type: null, hash: false, multiples: false, bytesReceived: null, bytesExpected: null, _parser: null, _flushing: 0, _fieldsSize: 0, openedFiles: [] }

通过以上信息我们可以看到 文件上传到’C:\Users\ADMINI~1\AppData\Local\Temp ,然后我查找这个路径,发现文件确实上传到这里了。 然后我有在app.post(’/upload’, function(req, res){

    var form = new formidable.IncomingForm();
form.uploadDir = './public/images/';    //上传目录
form.keepExtensions = true;             //保留后缀格式
form.maxFieldsSize = 2*1024*1024;       //文件大小
console.log('new formidable',form);
return res.redirect('/');              //这是为了测试}  

测试后发现打印出来的 uploadDir: ‘./public/images/’, 说明上传路径改变了 但是文件还是保存在’C:\Users\ADMINI~1\AppData\Local\Temp。

是我的思路错了么? 还是不使用bodyParser()就不能使用forimidable . 到底该如何将文件上传到指定的目录呢?并且要删掉那些上传的空文件??求各位大大赐教 不胜感激!! 要上班走了 ,写的匆忙 见谅!!


5 回复

要在不使用 body-parser 的情况下使用 formidable 实现多文件上传,你需要确保 formidable 正确地解析请求并处理文件上传。以下是一个完整的示例,展示如何配置和使用 formidable 来处理文件上传。

安装必要的依赖

首先,确保你已经安装了 expressformidable

npm install express formidable

项目结构

假设你的项目结构如下:

project-root/
├── app.js
├── index.js
├── views/
│   └── upload.ejs
└── public/
    └── images/

app.js

const express = require('express');
const formidable = require('formidable');
const path = require('path');
const app = express();
const port = 3000;

// 设置静态文件目录
app.use(express.static(path.join(__dirname, 'public')));

// 设置模板引擎
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');

// 路由
app.get('/', (req, res) => {
    res.render('upload');
});

app.post('/upload', (req, res) => {
    const form = new formidable.IncomingForm();
    
    // 配置 formidable
    form.uploadDir = path.join(__dirname, 'public/images');
    form.keepExtensions = true;
    form.maxFieldsSize = 2 * 1024 * 1024; // 2MB

    form.parse(req, (err, fields, files) => {
        if (err) {
            console.error('Error parsing form:', err);
            return res.status(500).send('File upload failed.');
        }

        // 检查是否有空文件
        Object.values(files).forEach(file => {
            if (file.size === 0) {
                // 删除空文件
                fs.unlinkSync(file.path);
                console.log(`Empty file removed: ${file.path}`);
            }
        });

        res.send('Files uploaded successfully!');
    });
});

app.listen(port, () => {
    console.log(`Server running at http://localhost:${port}/`);
});

upload.ejs

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Upload Files</title>
</head>
<body>
    <h1>Upload Multiple Files</h1>
    <form method="POST" action="/upload" enctype="multipart/form-data">
        <input type="file" name="file1" multiple /><br>
        <input type="file" name="file2" multiple /><br>
        <input type="file" name="file3" multiple /><br>
        <input type="submit" value="Upload" />
    </form>
</body>
</html>

解释

  1. 配置 formidable:

    • form.uploadDir 指定文件上传的目标目录。
    • form.keepExtensions 保留文件的扩展名。
    • form.maxFieldsSize 限制单个字段的最大大小。
  2. 处理文件上传:

    • form.parse 回调函数中,你可以访问上传的文件列表 (files)。
    • 检查每个文件的大小,如果为零则删除该文件。
  3. 模板:

    • 使用 EJS 模板引擎渲染上传表单。
    • 表单的 enctype 属性设置为 multipart/form-data,以支持文件上传。

通过这种方式,你可以使用 formidable 在 Express 中处理多文件上传,并将文件保存到指定的目录。


如果有什么思路,也请赐教

uploadDir目录要加上绝对路径,_dirname

我不知道你是什么问题,不过我贴我上传文件的模块给你吧,事实上,上传多个文件有专门的module,我用的是busboy

router.post('/upload',function(req,res){
  req.pipe(req.busboy)
  //要上传的文件数目
  var fileNum = 3;
  var fileCount = 0;
  var filepath = path.join(path.normalize(__dirname + '/..'),'public','images')
  req.busboy.on('file',function(fieldname,file,filename){
  //  console.log('++upload ' + filepath+'/'+filename)
    var fstream
    if(filename !== ""){
      fstream = fs.createWriteStream(filepath+'/'+filename.trim());
      file.pipe(fstream);
    }
    fstream.on('close', function () {
      if(++fileCount == fileNum)
        res.redirect('/');
    });
  })

要使用 formidable 实现多文件上传而不使用 body-parser 或者 connect-multiparty,你需要确保 formidable 正确配置并处理请求。以下是完整的示例代码及说明:

示例代码

app.js

const express = require('express');
const app = express();
const port = 3000;

app.use(express.json());
app.use(express.urlencoded({ extended: true }));

app.get('/', (req, res) => {
  res.sendFile(__dirname + '/upload.ejs');
});

app.post('/upload', (req, res) => {
  const form = new formidable.IncomingForm();

  form.uploadDir = './public/images/';    // 设置上传目录
  form.keepExtensions = true;             // 保留文件扩展名
  form.maxFieldsSize = 2 * 1024 * 1024;   // 最大字段大小为2MB

  form.parse(req, (err, fields, files) => {
    if (err) {
      console.error('Upload error:', err);
      res.status(500).send('File upload failed');
      return;
    }

    // 遍历所有上传的文件
    Object.values(files).forEach(file => {
      if (file.size === 0) {
        // 删除空文件
        fs.unlinkSync(file.path);
      } else {
        // 移动文件到目标位置
        fs.renameSync(file.path, './public/images/' + file.name);
      }
    });

    res.send('Files uploaded successfully');
  });
});

app.listen(port, () => {
  console.log(`Server running at http://localhost:${port}`);
});

说明

  1. 引入模块:首先需要引入 expressformidable 模块。
  2. 设置中间件:使用 express.json()express.urlencoded() 中间件处理 JSON 和 URL 编码的数据。
  3. 处理 GET 请求:提供一个简单的 GET 请求处理程序,用于渲染上传表单。
  4. 处理 POST 请求:在 POST 请求处理程序中创建一个新的 formidable.IncomingForm 对象,并进行配置:
    • uploadDir:设置上传文件的目录。
    • keepExtensions:保留文件的扩展名。
    • maxFieldsSize:设置最大字段大小。
  5. 解析请求:调用 form.parse(req, callback) 解析请求数据,并在回调函数中处理上传的文件:
    • 如果发生错误,返回错误信息。
    • 遍历所有上传的文件,如果文件大小为零,则删除文件;否则,移动文件到目标目录。

这样就可以正确地将文件上传到指定目录,并删除空文件。希望这能解决你的问题。

回到顶部