在 Express Route 中使用 Multer? (使用 MEANJS)

Posted

技术标签:

【中文标题】在 Express Route 中使用 Multer? (使用 MEANJS)【英文标题】:Use Multer in Express Route? (Using MEANJS) 【发布时间】:2015-03-03 08:47:57 【问题描述】:

我正在使用Multer 在 Express 4 中上传图像。但是,这些示例都显示 Multer 在 express 文件中被定义为中间件。我想在我的应用程序路由本身中定义一些 Multer 行为。这可能吗?我需要的最终结果是让我的路由函数在将服务器响应发送到浏览器之前识别上传何时完成,因此可以向用户显示图像(现在我只显示部分图像,因为文件尚未完成上传)。

当前的工作代码

express.js

// Require Multer as module dependency.
var multer = require('multer');

// Using Multer for file uploads.
app.use(multer(
    dest: './public/profile/img/',
    limits: 
        fieldNameSize: 50,
        files: 1,
        fields: 5,
        fileSize: 1024 * 1024
    ,
    rename: function(fieldname, filename) 
        return filename;
    ,
    onFileUploadStart: function(file) 
        if(file.mimetype !== 'image/jpg' && file.mimetype !== 'image/jpeg' && file.mimetype !== 'image/png') 
            return false;
        
    
));

server_routes.js

app.route('/users/image').post(server_controller_file.imageUpload);

server_controller_file.js

exports.imageUpload = function(req, res) 
// Check to make sure req.files contains a file, mimetypes match, etc., then send appropriate server response.
;

理想情况下,我的 server_controller_file.js 将包含一些检查以确保文件完成上传,例如(注意:这是假设的/理想的,不是实际的工作代码)...

var multer = require('multer');
exports.imageUpload = function(req, res) 
    multer(
        onFileUploadComplete: function(file) 
            res.send();
        
    );

同样,现在节点的异步特性导致浏览器在收到成功响应后立即认为上传完成,因此当我更新 url 以显示图像时,它只显示部分。感谢您的帮助!

【问题讨论】:

你能在 onFileUploadComplete 函数中得到file.path 吗? 因为multer作为中间件工作,我认为它在你的server_controller_file中不起作用。所以你不知道它何时完成上传文件。看这个例子:codeforgeek.com/2014/11/file-uploads-using-node-js @RyanYiada 我可以在 onFileUploadComplete 函数中访问 file.path,但它仍然无法与我的路由器通信。您链接到的文章很好 - 它有一个变量“完成”,它在中间件和路由器的范围内,但由于我的中间件和路由器位于不同的文件中,我的中间件变量超出了路由器的范围。跨度> @aikorei,express.js 是主服务器文件对吗? @shankarmsr 不,有一个单独的 server.js 文件可以启动所有内容,并包含 express.js 文件。 【参考方案1】:

其实你可以用另一种方法做你想做的事:

var express = require('express');
var multer  = require('multer');
var upload = multer( dest: './uploads/');
var app = express();

app.get('/', function(req, res)
  res.send('hello world');
);

// accept one file where the name of the form field is named photho
app.post('/', upload.single('photho'), function(req, res)
    console.log(req.body); // form fields
    console.log(req.file); // form files
    res.status(204).end();
);

app.listen(3000);

【讨论】:

与标记为答案的解决方案相比,这是一种更好的方法。它优化了每条路由的中间件。如果将多个中间件链接在一起,您会发现 express 使用流,但这并不完全适用于中间件。事件不在中间件之间通过管道传输。如果您在链中使用两个快速中间件,并且每个中间件都尝试捕获所有流事件并在所有事件完成后调用 next(),则第二个中间件将不再接收所需的事件。在这种情况下,您需要优化每个路由的中间件。 只是一个简单的问题,为什么它被封装在 [ ] 中,这是否像定义一个链而不是使用下一个函数? 如果目标文件夹名称取决于 req.body 参数,您的答案将不起作用,那么您将如何做??? 如果我想通过rest api调用上传怎么办。我应该将什么传递给 single() 函数? 我正在努力做@SudhanshuGaur 提到的事情。我正在使用 multer 将图像上传处理为表单的一部分,但需要将图像重命名为表单中另一个输入的值。填充 req.body 变量后,似乎无法将新文件名传递给 multer。【参考方案2】:

好的,我实际上只是写了原始数据。如果将inMemory 设置为true,它会将原始数据发送到req.files.file.buffer。这是最终的可行解决方案:

express.js

// Using Multer for file uploads.
app.use(multer(
    dest: './public/profile/img/',
    limits: 
        fieldNameSize: 50,
        files: 1,
        fields: 5,
        fileSize: 1024 * 1024
    ,
    rename: function(fieldname, filename) 
        return filename;
    ,
    onFileUploadStart: function(file) 
        console.log('Starting file upload process.');
        if(file.mimetype !== 'image/jpg' && file.mimetype !== 'image/jpeg' && file.mimetype !== 'image/png') 
            return false;
        
    ,
    inMemory: true //This is important. It's what populates the buffer.
));

server_controller_file.js

exports.imageUpload = function(req, res) 
    var file = req.files.file,
        path = './public/profile/img/';

    // Logic for handling missing file, wrong mimetype, no buffer, etc.

    var buffer = file.buffer, //Note: buffer only populates if you set inMemory: true.
        fileName = file.name;
    var stream = fs.createWriteStream(path + fileName);
    stream.write(buffer);
    stream.on('error', function(err) 
        console.log('Could not write file to memory.');
        res.status(400).send(
            message: 'Problem saving the file. Please try again.'
        );
    );
    stream.on('finish', function() 
        console.log('File saved successfully.');
        var data = 
            message: 'File saved successfully.'
        ;
        res.jsonp(data);
    );
    stream.end();
    console.log('Stream ended.');
;

【讨论】:

【参考方案3】:

我找到了一个 busboy 的例子:

exports.upload = function (req, res, next) 
   req.busboy.on('file', function (fieldname, file, filename, encoding, mimetype) 
       // ....
   );

   req.pipe(req.busboy);
;

multer 也是个管家:

 req.pipe(busboy);

https://github.com/expressjs/multer/blob/master/index.js#206

【讨论】:

你是说做我想做的事对 Multer 不起作用?那我应该改用 Busboy 吗? 直到我深入了解下,我才明白,但 multer 只是被包裹起来并作为中间件实现的杂工。我需要挂钩路径中 busboy 的事件,所以直接使用 busboy 是有意义的。 @aikorei 正如 eephillip 所说,multer 只是 busboy 包装器。multer 将返回 busboy。

以上是关于在 Express Route 中使用 Multer? (使用 MEANJS)的主要内容,如果未能解决你的问题,请参考以下文章

Express Route & Socket io

Express Route Not Called Node JS

node之post提交上传

一根Express Route同时支持ARM和ASM的VNET

express 中导入变量的问题,错误:Route.get() 需要回调函数

在 Express 中对路线进行分组