You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MERN栈中Multer+Cloudinary视频上传失败:req.file读取异常

MERN栈视频上传故障排查

我在MERN栈中基于Multer和Cloudinary构建了文件上传功能,图片上传正常,但尝试上传视频时遇到以下问题:

  1. 初始报错:

Cannot read property 'path' of undefined

  1. 修改后端代码后报错变为:

Cannot read property "headers" of undefined

  1. 目前通过console.log()能输出正确请求头:

{"x-powered-by":"Express","access-control-allow-origin":"*","content-type":"application/json; charset=utf-8","content-length":"2","etag":"W/"2-vyGp6PvFo4RvsFtPoIWeCReyIC8""}

现在无错误提示,但视频未上传成功,仪表盘仅显示空边框。我排查过前端到Redux切片、Redux服务的FormData,"src"字段均为对应视频文件,猜测可能是时序问题,恳请帮忙排查。


当前后端代码

const upload = require("../utils/multer");
const cloudinary = require("../utils/cloudinary");
const multer = require("multer");
const path = require("path");
const onHeaders = require("on-headers");
function responseDebugger() {
    console.log(JSON.stringify(this.getHeaders()))
  }
//create
router.post("/", (req,res,next)=>{
    onHeaders(res, responseDebugger)
    res.json({})
})
router.post("/", verifyTokenAndAuthorization, async (req,res)=>{
    function fileupload(req,res,next){
        const uploadVideo = upload.single("src");
    uploadVideo(req,res, function(err){
        if(err instanceof multer.MulterError){
            console.log(err);
        } else if(err){
            console.log(err);
        }
        next();
    })
}
fileupload();
try{
    const result = await cloudinary.uploader.upload_large(req.file.path, {
        upload_preset: "Mern_redux-practice",
        resource_type: "video",
    }
    );
    const newVideos= new Videos({
        cloudinary_id: result.public_id,
        ressort: req.body.ressort,
        theme: req.body.theme,
        title:req.body.title,
        src: result.secure_url,
    })
    const savedVideos= await newVideos.save();
    res.status(200).json(savedVideos);
} catch(error){
    res.status(403)
    console.log(error)
    throw new Error("Action failed");
}
});

Multer存储配置

const maxSize = 5 * 1024 *1024;
 const storage = multer.diskStorage({
        destination:(req,file, callback)=>{
            callback(null,  path.resolve(process.cwd(), 'frontside/public/uploads'));
        },
        fileName: (req, file, callback)=>{
            callback(null, Date.now()+ "--"+ path.extname(file.originalname));
            console.log(req.file)
        },
    })

const upload = multer({
    storage:storage,
    fileFilter:(req,file,callback)=>{
        if(
            file.mimetype == "image/png"||
            file.mimetype == "image/jpg" ||
            file.mimetype == "image/jpeg" ||
            file.mimetype == "video/mp3" ||
            file.mimetype == "video/mp4"
        ){
            callback(null, true);
        } else{
            callback(null,false)
            return callback(new Error("Only .png, .jpg, .jpeg, .mp3, .m4 allowed"))
        }
    },
    limits:{fileSize: maxSize}
});

前端HTTP请求代码

const createVideos = async (videosData, token)=>{
    if(videosData){
        for(let value of videosData){
            console.log(value);
        }
    }
    const config = {
        headers:{
        'Content-Type': 'application/json',
        token: `Bearer ${token}` 
        }
    }
    const response = await axios.post(API_URL, videosData, config);
    console.log(response.data);
    return response.data;
}

故障原因及解决方案

1. 前端请求头错误

上传文件必须使用multipart/form-data格式,手动设置Content-Type: application/json会导致后端无法解析FormData中的文件。
修复:
移除手动设置的Content-Type,axios会自动根据FormData生成正确请求头:

const createVideos = async (videosData, token)=>{
    if(videosData){
        for(let value of videosData){
            console.log(value);
        }
    }
    const config = {
        headers:{
        token: `Bearer ${token}` 
        }
    }
    const response = await axios.post(API_URL, videosData, config);
    console.log(response.data);
    return response.data;
}

2. 后端路由冲突+Multer调用错误

  • 两个router.post("/")路由会导致第一个优先匹配,直接返回空JSON,带验证的业务路由永远不会执行。
  • fileupload()调用时未传递req/res/next参数,Multer无法获取请求对象,req.file自然为undefined。
    修复:
    删除无用路由,将Multer作为路由中间件直接挂载:
const upload = require("../utils/multer");
const cloudinary = require("../utils/cloudinary");
const multer = require("multer");
const path = require("path");
const onHeaders = require("on-headers");
function responseDebugger() {
    console.log(JSON.stringify(this.getHeaders()))
  }

//create - 合并为单个路由,Multer作为中间件直接使用
router.post("/", verifyTokenAndAuthorization, upload.single("src"), async (req,res)=>{
    onHeaders(res, responseDebugger)
    try{
        // 先校验文件是否存在
        if(!req.file) {
            return res.status(400).json({error: "No video file uploaded"});
        }
        const result = await cloudinary.uploader.upload_large(req.file.path, {
            upload_preset: "Mern_redux-practice",
            resource_type: "video",
        });
        const newVideos= new Videos({
            cloudinary_id: result.public_id,
            ressort: req.body.ressort,
            theme: req.body.theme,
            title:req.body.title,
            src: result.secure_url,
        })
        const savedVideos= await newVideos.save();
        res.status(200).json(savedVideos);
    } catch(error){
        console.log(error)
        res.status(403).json({error: "Action failed"});
    }
});

3. Multer配置错误

  • diskStorage中的方法名是filename(小写n),不是fileName,大小写错误会导致文件存储失败。
  • 5MB的大小限制对视频来说过小,建议调整到合理值(如50MB)。
  • video/mp3是错误的MIME类型,正确应为audio/mpeg,错误类型会导致视频被过滤。
    修复:
const maxSize = 50 * 1024 *1024; // 调整为50MB
const storage = multer.diskStorage({
        destination:(req,file, callback)=>{
            callback(null,  path.resolve(process.cwd(), 'frontside/public/uploads'));
        },
        filename: (req, file, callback)=>{ // 修正方法名
            callback(null, Date.now()+ "--"+ path.extname(file.originalname));
        },
    })

const upload = multer({
    storage:storage,
    fileFilter:(req,file,callback)=>{
        const allowedTypes = [
            "image/png",
            "image/jpg", 
            "image/jpeg", 
            "audio/mpeg", // 修正MP3的MIME类型
            "video/mp4"
        ];
        if(allowedTypes.includes(file.mimetype)){
            callback(null, true);
        } else{
            callback(new Error("Only .png, .jpg, .jpeg, .mp3, .mp4 allowed")); // 修正错误提示
        }
    },
    limits:{fileSize: maxSize}
});

4. 错误处理优化

后端catch块中throw new Error无法将错误返回前端,应直接用res.status().json()返回错误信息,避免请求挂起。


内容的提问来源于stack exchange,提问作者Roman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 20:57:26