Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/node.js/39.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 完全控制nodejs中使用ajax发送的文件_Javascript_Node.js_Multer - Fatal编程技术网

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

Javascript 完全控制nodejs中使用ajax发送的文件,javascript,node.js,multer,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.arr

我使用
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
其中
5a9e881c3ebb4e1bd8911126是
mongoose
保存的产品文档的id

  • 如何解决这个命名问题
  • multer
    是我想要完全控制文件的最佳解决方案吗
  • 使用另一个节点包是否有更好的方法
  • 多部分/数据表单
    数据URL base64
    的形式发送图像好吗

  • 您不能仅在
    (1)
    中设置名称,因为此时您还不知道产品的ID


    您不能仅在
    (2)
    中设置名称,因为此时文件已经保存(使用
    文件名(req,file,cb)
    函数生成的文件名)

    因此,我认为最好的解决方案可能是在上传文件后移动它们

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

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

    为此,可以使用
    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)
        })
    })
    

    这很容易,只要您了解express的工作原理。因此,在开始解决问题之前,有一个清晰的理解是很重要的

    当您有下面这样的快速代码时

    router.post('/abc', function(req, res) {res.send('hello world');})
    
    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');
        },
    });
    
    Express传递来自多个中间件/功能链的请求。现在,每个函数获得
    req、res、next
    参数。下一个
    是函数,假设中间件在处理完成时调用该函数。如果中间件决定不调用
    next
    ,则请求在此结束,不再调用更多的中间件

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

    router.post('/products', upload.array('images'), (req, res, next) => {...}
    
    您首先使用了
    upload.array('images')
    ,然后使用了实际的产品
    创建
    code。所以我将展示两种方法来解决这个问题

    再多一个中间件来重命名文件

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

    颠倒处理顺序

    在这种方法中,您首先创建产品,然后进行图像处理

    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);
    
    用邮递员测试也很好

    编辑:2018年3月19日

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

    router.post('/abc', function(req, res) {res.send('hello world');})
    
    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');
        },
    });
    
    这将确保您获得该产品的所有文件。现在来回答您的问题

    如何解决此命名问题?

    这个答案已经做到了

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

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

    使用另一个节点包是否有更好的方法?

    我找不到很多软件包。但是如果你想的话,你可以去探索

    以多部分/数据表单或数据URL base64的形式发送图像好吗?


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

    multer只是一个临时保存
    multipart/form数据的解决方案。
    。最佳实践是使用您自己的逻辑操作临时数据(上传到云端,更改文件名,使用您自己的id进行散列,并将id存储在数据库中,等等)。@gokc以及如何使用我自己的逻辑操作数据而不使用
    multer
    ?谢谢男士:)在
    反转处理顺序
    方法中,仅保存最后一个文件,因为单个
    产品id
    将有多个文件,我可以通过指定类似
    新日期()的内容来解决此问题。getTime()
    @Youssef,请查看回答末尾的最新编辑谢谢男士:)你能回答我问题中的其他几点吗?