React+Express文件上传时req.file.buffer为undefined如何解决
问题场景
- 前端基于React.js开发文件上传表单,逻辑如下:
- 文件选择触发
handleUpload方法时,将选中的文件存入状态formvalue的recevierImages字段 - 点击提交按钮触发
submitData方法时,将formvalue转换为FormData格式,通过createDonation接口发起上传请求
- 文件选择触发
- 前端实现代码:
const handleUpload = (e) => { setFormvalue({ ...formvalue, recevierImages: e.target.files[0] }); }; const submitData = () => { console.log(formvalue); dispatch(createDonation(getFormData(formvalue))); }; <Form> <Form.Item name="donationImage" label="Upload Image"> <input type="file" onChange={(e) => handleUpload(e)} /> </Form.Item> </Form> <Button onClick={submitData} type="primary"> Create </Button>
- 后端基于Express.js开发接口,使用Multer中间件处理文件上传,逻辑如下:
- 配置Multer的diskStorage存储策略
- 对
/createPOST接口使用uploadImage中间件,处理字段名为recevierImages的单文件上传
- 后端路由实现代码:
const express = require("express"); const multer = require("multer"); const donationController = require("../controller/donationController"); const router = express.Router(); const multerStorage = multer.diskStorage({ destination: function (req, file, callBack) { callBack(null, ""); }, }); const uploadImage = multer({ storage: multerStorage }).single("recevierImages"); router.post("/create", uploadImage, donationController.createDonation); router.patch("/update", donationController.updateDonation); module.exports = router;
- 异常现象:在donationController.js的
createDonation方法中访问req.file.buffer时值为undefined,控制器代码如下:
const createDonation = async (req, res) => { try { console.log(req.file.buffer); } catch (error) { console.log(error); res.status(500).send(error); } } module.exports = { createDonation, };
问题根因
req.file.buffer为undefined是Multer存储模式配置和使用方式不匹配导致的,核心原因有两个:
- 存储模式特性差异:当前使用的是
diskStorage磁盘存储模式,该模式下Multer会将上传的文件直接写入服务器本地磁盘,不会在内存中保留文件的二进制Buffer数据,因此不会挂载req.file.buffer属性。req.file.buffer仅在memoryStorage内存存储模式下才会存在,该模式会把文件以二进制Buffer的形式存在内存中,不会自动写入本地磁盘。 - 额外配置隐患:当前
diskStorage的destination回调传入的存储路径为空字符串,即使不需要访问buffer,该配置也会导致文件写入时因找不到目标目录抛出IO错误。
修复方案
根据业务需求二选一即可:
方案1:需要获取文件Buffer做内存处理(如图片压缩、上传第三方对象存储)
将Multer的存储模式替换为memoryStorage即可,修改后的Multer配置代码如下:
// 替换diskStorage为memoryStorage,不需要配置destination和filename const multerStorage = multer.memoryStorage(); const uploadImage = multer({ storage: multerStorage }).single("recevierImages");
配置后即可在控制器中正常访问req.file.buffer获取文件二进制数据。
方案2:需要将文件存储在服务器本地磁盘
这种场景下不需要访问req.file.buffer,只需要修正diskStorage的存储路径配置即可,Multer会自动把文件写入指定目录,可以通过req.file获取文件的存储路径、原始文件名、MIME类型等元信息:
const path = require("path"); const multerStorage = multer.diskStorage({ destination: function (req, file, callBack) { // 替换为实际的文件存储目录绝对路径,比如项目根目录下的uploads文件夹 callBack(null, path.join(__dirname, "../uploads")); }, filename: function (req, file, callBack) { // 自定义文件名避免重名覆盖,比如用时间戳+随机数+原始后缀 const ext = path.extname(file.originalname); callBack(null, `${Date.now()}-${Math.round(Math.random() * 1e9)}${ext}`); } }); const uploadImage = multer({ storage: multerStorage }).single("recevierImages");
配置后控制器中可通过req.file.path拿到文件的本地存储路径,req.file.filename拿到存储后的文件名,不需要访问buffer属性。
注意:请提前创建好你配置的destination目录,否则Multer写入文件时会抛出目录不存在的错误。
内容的提问来源于stack exchange,提问作者Saif Farooqui
相关产品推荐
相关产品推荐

