Multer多POST请求下不同存储引擎的配置问题
我正在开发一个文件上传至服务器的应用,使用Multer将文件保存到服务器文件夹中。我尝试让/uploads路由接收多个文件(目前仅两张图片),并分别通过不同的Multer存储引擎存储:
存储引擎代码
const serumPresetsStorageCfg = multer.diskStorage({ destination: (req, file, cb) => { cb(null, "./src/serum-presets"); }, filename: (req, file, cb) => { cb(null, Date.now() + " -- " + file.originalname); }, }); const serumPresetsStorage = multer({storage: serumPresetsStorageCfg}); //********************************************************************** const showcaseImageStorageCfg = multer.diskStorage({ destination: (req, file, cb) => { cb(null, "./src/showcase-image"); }, filename: (req, file, cb) => { cb(null, Date.now() + " -- " + file.originalname); }, }); const showcaseImageStorage = multer({storage: showcaseImageStorageCfg});
/uploads路由代码
app.post("/uploads", serumPresetsStorage.single("kit-image"), (req,res) => { console.log(req.file); }); app.post("/uploads", showcaseImageStorage.single("showcase-image"), (req,res) => { console.log(req.file); });
目前kit-image的POST请求可正常工作,但使用Postman发送showcase-image字段的POST请求时,出现错误:MulterError: Unexpected field。我原本以为在.single("")中指定不同字段即可让/uploads路由处理不同POST请求,但实际并非如此。请问是否有办法让/uploads路由接收这些不同POST请求,并分别通过不同存储引擎处理?
问题出在Express的路由匹配逻辑:它会按定义顺序匹配路由,第一个/uploads路由的中间件serumPresetsStorage.single("kit-image")只接受kit-image字段,当你发送showcase-image请求时,这个中间件会直接抛出字段不匹配的错误,根本到不了第二个路由。
以下是两种可行的解决方法:
方案一:自定义动态存储引擎
把两个存储引擎的逻辑合并,根据上传文件的字段名动态选择存储路径,再用upload.fields()同时监听多个字段:
const customStorage = multer.diskStorage({ destination: (req, file, cb) => { let targetFolder = ""; switch(file.fieldname) { case "kit-image": targetFolder = "./src/serum-presets"; break; case "showcase-image": targetFolder = "./src/showcase-image"; break; default: return cb(new Error("不支持的文件字段")); } cb(null, targetFolder); }, filename: (req, file, cb) => { cb(null, Date.now() + " -- " + file.originalname); }, }); const upload = multer({ storage: customStorage }); app.post("/uploads", upload.fields([ { name: "kit-image", maxCount: 1 }, { name: "showcase-image", maxCount: 1 } ]), (req, res) => { // req.files会按字段名分类存储上传的文件 console.log(req.files); res.status(200).send("文件上传成功"); });
这种方式支持单独传kit-image、单独传showcase-image,甚至同时传两个文件,都能自动存储到对应文件夹。
方案二:路由中间件动态选择存储引擎
如果想保留原有两个独立的存储引擎配置,可以写一个中间件,先判断请求中的文件字段,再调用对应的Multer处理函数:
const handleUpload = (req, res, next) => { // 检查请求中的文件字段 const fileField = Object.keys(req.files || {})[0] || (req.body && Object.keys(req.body).find(key => req.body[key] instanceof File)); if (fileField === "kit-image") { serumPresetsStorage.single("kit-image")(req, res, next); } else if (fileField === "showcase-image") { showcaseImageStorage.single("showcase-image")(req, res, next); } else { next(new Error("未检测到有效的文件字段")); } }; app.post("/uploads", handleUpload, (req, res) => { console.log(req.file); res.status(200).send("文件上传成功"); });
这种方式更灵活,适合两个存储引擎逻辑差异较大的场景。
内容的提问来源于stack exchange,提问作者poltergaz

