我使用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
最佳解决方案,因为我希望完全控制我的文件? multipart/data-form
或data URL base64
答案 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);
使用邮差测试它可以正常工作
编辑: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转换。但这也是一个意见问题。