完全控制在nodejs中使用ajax发送的文件

时间:2018-03-14 11:19:20

标签: javascript node.js multer

我使用multer来解析使用multipart/data-form发送为axios的多个文件

...

const storage = multer.diskStorage({
    destination: './gallery',
    filename(req, file, cb) {
      (1) ....
    },
});

const upload = multer({ storage });

router.post('/products', upload.array('images'), (req, res, next) => {

    Product.create(...)
       .then((product) => {
          (2) ... 
       })
       .catch(..)
})

...

此时一切正常,我的图像已保存。

问题是我想在(1)(2)中制作一个循环并命名我的文件

files.forEach((file, index) => {

   // rename file to => product_id + '_' + index + '.jpeg'
}

例如,如果我有3个文件,他们将被命名为

5a9e881c3ebb4e1bd8911126_1.jpeg

5a9e881c3ebb4e1bd8911126_2.jpeg

5a9e881c3ebb4e1bd8911126_3.jpeg

其中5a9e881c3ebb4e1bd8911126mongoose保存的产品文档的ID。

  1. 如何解决这个命名问题?
  2. multer最佳解决方案,因为我希望完全控制我的文件?
  3. 是否有更好的方法与另一个节点包?
  4. multipart/data-formdata URL base64
  5. 的形式发送图片是否合适?

2 个答案:

答案 0 :(得分:1)

您无法完全在(1)中设置名称,因为此时您还不知道产品的ID。

您无法完全在(2)中设置名称,因为此时文件已经保存(文件名由filename(req, file, cb)函数生成)。

所以我认为最好的解决方案可能是在文件上传后移动文件。

这可以在(2)中完成。处理路由器中的文件时,req.files将是已上载的文件数组。

Product.create的承诺回调中,您可以访问产品(ID需要的产品)和文件列表(您需要的号码)。

为此,您可以使用fs.rename(oldPath, newPath, callback)

https://nodejs.org/docs/latest/api/fs.html#fs_fs_rename_oldpath_newpath_callback

这样的事情应该有效:

Product.create(...).then((product) => {
    req.files.forEach((file, index) => {
        // file.path is the full path to the file that was uploaded.

        // newPath is where you want to put it.
        // Let's use the same destination and just change the filename.

        const newPath = file.destination + product.id + '_' + index

        fs.rename(file.path, newPath)
    })
})

答案 1 :(得分:1)

这很简单,只要你了解快递是如何运作的。所以在跳到解决方案之前,重要的是要有一个清晰的理解。

当你有如下的快递代码时

router.post('/abc', function(req, res) {res.send('hello world');})

Express传递来自中间件/函数链的请求。现在每个函数都有req, res, next个参数。 next是函数,中间件假定在处理完成时调用。如果中间件决定不调用next,则请求在那里结束,并且不再进一步调用中间件。

当我们使用function(req, res) {res.send('hello world');}时,我们根本没有使用next参数,这意味着我们对任何其他代码都不感兴趣。现在回到我们的问题

router.post('/products', upload.array('images'), (req, res, next) => {...}

您先使用upload.array('images'),然后使用实际产品creation代码。所以我会展示两种方法来解决这个问题

另一个重命名文件的中间件

router.post('/ products',upload.array('images'),(req,res,next)=> {

Product.create(...)
   .then((product) => {
      req.product = product
      next();
   })
   .catch(..)
}, (req, res, next) => {
   //Get the product id using req.product
   //Move the files as per the name you desire
})

撤消处理订单

在这种方法中,您首先创建产品,然后让图像处理发生。我已经为显示相同的

创建了一个示例
let express = require('express');
let bodyParser = require('body-parser');
app = express();
let multer = require('multer');

const storage = multer.diskStorage({
    destination: './gallery',
    filename: (req, file, cb) => {
        console.log('Product id - ' + req.product_id);
        cb(null, req.product_id + '.js');
    },
});

const upload = multer({ storage });

app.all('/', (req, res, next) => {
    console.log('Hello you');
    promise = new Promise((resolve) => {
        // simulate a async product creation
        setTimeout(() => resolve(1234), 100);
    });

    promise.then((product_id) => {
        console.log('create the product and get the new product id')
        // set the product id in the request object, so the multer
        // filename function can access it
        req.product_id = product_id;
        res.send('uploaded files');
        if (next)
            next();
    });
}, upload.array('images'));

module.exports = {
    app
};

app.listen(8020);

使用邮差测试它可以正常工作

Postman

Uploaded file

编辑:2018年3月19日

对于多个文件,您可以轻松更新文件名功能代码,如下所示

const storage = multer.diskStorage({
    destination: './gallery',
    filename: (req, file, cb) => {
        req.file_id = req.file_id || 0;
        req.file_id++;
        console.log('Product id - ' + req.product_id);
        cb(null, req.product_id +'_' + req.file_id +'.js');
    },
});

这将确保您获得该产品的所有文件。现在回答你的问题

  

如何解决此命名问题?

这个答案已经做到了

  

是最好的解决方案,因为我希望完全控制我的文件?

我不能说,只要它起作用并做你想做的事,它应该足够好了

  

使用其他节点包有更好的方法吗?

我找不到很多包裹。但是如果你想要

,你可以探索this
  

以多部分/数据形式或数据网址base64发送图片是否合适?

我会使用multipart/data-form,因此客户端不需要进行base64转换。但这也是一个意见问题。