我目前正在使用Multer和一个自定义存储引擎,该引擎可以将文件上传到请求中指定的位置。我目前正在从查询中获取目的地和其他几个参数,但我更喜欢将所有输入数据合并到表单数据中。这个目标输入需要一些额外的验证,需要访问res
和next
。当前的实现如下:
upload(req, res, next) {
// Ideally this would be `req.body.destination`;
const destination = req.query.destination;
/* Validation ... */
return multer({
storage: new CustomStorage(destination),
}).single('file')(req, res, next);
}
但是,Multer需要在验证之前运行,以便首先将表单数据解析为req.body
。我试图通过在存储引擎之前运行第二个Multer示例来解决这个问题--这个示例将忽略文件并将所有文本字段解析为req.body
。具体实施如下:
multer({
fileFilter: (req, file, cb) => { return cb(null, false); },
}).any();
运行此命令确实允许我在上传中间件中访问req.body
中的表单数据,但随后我收到以下错误:
Error: Unexpected end of form
at Multipart._final (/Users/robert/bucket/node_modules/busboy/lib/types/multipart.js:588:17)
at callFinal (node:internal/streams/writable:694:27)
at prefinish (node:internal/streams/writable:723:7)
at finishMaybe (node:internal/streams/writable:733:5)
at Multipart.Writable.end (node:internal/streams/writable:631:5)
at onend (node:internal/streams/readable:693:10)
at processTicksAndRejections (node:internal/process/task_queues:78:11) {
storageErrors: []
}
在阅读issue 1144后,我试图降级到Multer 1.4.3,这样做确实阻止了错误,但导致API路由错误,状态为400
,没有错误消息。
如何访问此处的表单数据字段?
1条答案
按热度按时间kyvafyod1#
正如您正确指出的那样,要使用任何内容填充
req.body
,需要首先运行Multer。只有当您调用Multer中间件时,req
流才会通过Busboy(Multer使用的多部分/表单数据请求解析器),字段和文件会被解析并填充,按照它们出现的顺序,到req.body
。这意味着,如果您在任何文件之前发送所有必要的字段,您的
CustomStorage._handleFile()
实现将可以访问req.body
,并填充字段。因此,为了直接回答您的问题,您可以在
CustomStorage._handleFile()
中实现字段验证-req.body
将填充字段,**但只有那些在任何文件之前收到的字段!**这里字段/文件的顺序很重要。这有几个缺点:
1.这将您的验证实现与Multer的API紧密联系在一起;
1.有时候,您可能没有发送/接收任何文件,但仍希望验证字段。
1.每次遇到一个文件时,验证将冗余地运行-如果您有3个文件,则对req.body的验证将运行三次。这应该不会对性能有很大的影响,但仍然不是很优雅。
Multer的设计不够灵活,不允许这样的定制逻辑,它不提供单独处理字段事件的功能,只提供文件事件。
我写了
pechkin
来解决这个问题。pechkin.parseFormData()
返回一个Promise
,当所有字段都被解析时,和如果遇到第一个文件(或请求结束)。fields
对象和一个files
AsyncIterator/AsyncIterable
。这意味着您可以对
fields
对象执行验证,然后才必须处理文件-文件不会被解析,处理,写入内存,保存在任何地方,直到您决定这样做。无需将您的功能 Package 到自定义存储引擎类中-文件可以作为Promise
或stream.Readable
示例提供。