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

Node.js Multer问题:使用upload.single()中间件时req.file始终为undefined

问题:Multer自定义上传中间件中req.file始终为undefined

我尝试实现一个可自定义(支持指定文件类型、目标文件夹等)的Multer文件上传中间件,文件上传功能能正常运行,但req.file始终返回undefined。以下是相关代码:

路由代码

router.patch('/profile-picture',
    [
        AsyncErrorWrapper(passport.verifyJwt()),
        AsyncErrorWrapper(singleFileUpload('/images/', ['image/png', 'image/jpeg'])),
    ], AsyncErrorWrapper(userController.updateProfilePicture))

singleFileUpload 中间件

const {uploadConfiguration, multerDelay} = require("../services/multer.service")

/**
 * 
 * @param {*} dest 目标文件夹(位于/tmp下)
 * @param {*} whitelist 允许上传的文件类型列表
 * @returns 
 */
module.exports = (dest, whitelist, name = 'file') => {
    return async (req, res, next) => {
        // 获取上传配置对象
        const upload = uploadConfiguration(dest, whitelist)

        // 调用upload.single
        upload.single(name)(req, res, next)

        // 尝试等待上传完成以解决req.file为undefined的问题
        await multerDelay()
        next()
    }
}

Multer服务代码

const uploadConfiguration = (dest, whitelist) => {
    // 存储配置
    const storage = multer.diskStorage({
        destination: (req, file, cb) => {
            // 设置目录
            const dir = `${tmpStorage}${dest}`
            mkdirp.sync(dir)
            cb(null, dir)
        },
        filename: (req, file, cb) => {
            cb(null, Date.now() + path.extname(file.originalname));
        },

    })

    // 上传过滤器
    const uploadFilter = (req, file, cb) => {

        if (!whitelist.includes(file.mimetype)) {
            return cb(new AppError('文件类型不允许', 400), false)
        }
        // 尝试解决后续中间件中req.file为undefined的问题
        req.file = file
        cb(null, true)
    }

    return multer({
        storage: storage,
        fileFilter: uploadFilter
    })
}

/**
 * 
 * @returns 一个在队列清空后resolve的Promise
 */
const multerDelay = () => {
    console.log('multerDelay');
    return new Promise((resolve) => setTimeout(() => resolve(), 0))
} 

控制器代码

const updateProfilePicture = async (req, res, next) => {
    
        console.log(req.file) // 输出undefined
        return res.status(200).json({msg: 'hi'})
    
}

问题原因分析

  1. 中间件执行顺序错误:你在singleFileUpload中手动调用upload.single(name)(req, res, next)后,又通过await multerDelay()和手动next()提前进入下一个中间件。但upload.single是异步处理文件上传的,它会在文件处理完成后才调用传入的next,而你手动调用的next会在Multer还没完成文件处理、赋值req.file时就触发,导致控制器中req.file为undefined。
  2. 错误手动赋值req.file:在uploadFilter中手动给req.file = file是多余且错误的,Multer会在文件成功存储后自动将完整的文件信息(包括存储路径、文件名等)赋值给req.file,此处的file只是原始文件对象,并非最终的处理结果。

解决方案

1. 修改singleFileUpload中间件

去掉多余的async包装、multerDelay和手动next(),直接返回Multer的中间件,让它自己处理流程:

const {uploadConfiguration} = require("../services/multer.service")

module.exports = (dest, whitelist, name = 'file') => {
    const upload = uploadConfiguration(dest, whitelist)
    // 直接返回multer的single中间件,由它负责调用next
    return upload.single(name)
}

2. 修正uploadFilter

移除手动赋值req.file的代码:

const uploadFilter = (req, file, cb) => {
    if (!whitelist.includes(file.mimetype)) {
        return cb(new AppError('文件类型不允许', 400), false)
    }
    cb(null, true)
}

3. 路由保持不变

原路由代码无需修改,AsyncErrorWrapper可以正常包裹修改后的singleFileUpload返回的中间件。

原理说明

Multer的upload.single()本身就是一个符合Express规范的中间件,它会在完成文件的存储、赋值req.file等操作后自动调用next(),不需要额外的异步等待或手动触发next。之前的包装逻辑破坏了Multer的原生执行流程,导致req.file还未被赋值就进入了控制器。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 00:15:42