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

React上传MP4至Express再转存Abyss云存储请求异常排查

问题描述

我找到一个视频云存储网站Abyss,它提供的上传文档是cURL形式:

curl -F "file=@demo.mp4" up.hydrax.net/MY_API_KEY

我尝试用React+ExpressJS实现这个功能,React端提交视频的代码如下:

const handleSubmit = async () => {
    let formData = new FormData()
    formData.append("file", selectVideo)
    await axios.post(
        `/film/add-episode/${_id}`,
        {
            formData,
        },
        {
            headers: {
                "content-type": "multipart/form-data",
            },
        }
    )
}

视频会发送到Express的POST路由,后端控制器代码如下:

const filmController = {
    addEpisode: async (req, res) => {
        const { formData } = req.body
        try {
            console.log(formData) // 从React传至Express的是FormData对象

            //API URL to upload video
            const response = await axios.post(
                "http://up.hydrax.net/MY_API_KEY_HERE",
                {
                    formData,
                },
                {
                    headers: {
                        "content-type": "multipart/form-data",
                    },
                }
            )
            console.log(response)
            res.json({ msg: "Success add episode" })
        } catch (err) {
            return res.status(500).json({ msg: err.message })
        }
    },
}

我需要在后端通过axios获取Abyss上传成功后生成的slug并存入MongoDB,但现在请求一直处于pending状态,文件也没上传到云存储,怀疑是FormData对象无法被识别为MP4文件。


问题原因及修复方案

你的代码存在两个核心错误,导致上传失败:

1. React端:FormData被错误包裹成普通对象发送

你在axios请求里把formData放在了一个对象中传递,这会破坏FormData的原始结构,Express无法正确解析文件。正确做法是直接把FormData作为请求体发送,且无需手动设置multipart/form-data头——axios会自动生成包含boundary的正确Content-Type。

修正后的React代码:

const handleSubmit = async () => {
    let formData = new FormData()
    formData.append("file", selectVideo)
    await axios.post(
        `/film/add-episode/${_id}`,
        formData // 直接传递FormData,不要包裹成对象
    )
}

2. Express端:未正确解析multipart请求,且转发时错误处理FormData

Express默认不支持解析multipart/form-data格式的请求,需要借助multer中间件处理文件上传;同时后端转发请求时,错误地将FormData包裹成对象,导致第三方API无法识别文件。

步骤1:安装multer

npm install multer

步骤2:配置Express路由使用multer

在路由文件中添加multer配置,用内存存储临时保存文件(适合转发到第三方API):

const multer = require('multer');
const upload = multer({ storage: multer.memoryStorage() });

// 路由中使用upload.single('file')解析单个文件
router.post('/film/add-episode/:_id', upload.single('file'), filmController.addEpisode);

步骤3:修正后端控制器代码

multer会将解析后的文件存入req.file,你需要基于这个文件对象重新构建FormData,再发送到Abyss的API:

const filmController = {
    addEpisode: async (req, res) => {
        try {
            // 从multer解析结果中获取文件信息
            const { originalname, buffer, mimetype } = req.file;

            // 构建用于上传到Abyss的FormData
            const uploadFormData = new FormData();
            uploadFormData.append('file', buffer, {
                filename: originalname,
                contentType: mimetype
            });

            // 发送请求到Abyss API
            const response = await axios.post(
                "http://up.hydrax.net/MY_API_KEY_HERE",
                uploadFormData, // 直接传递FormData
                {
                    headers: {
                        ...uploadFormData.getHeaders() // 自动生成正确的Content-Type
                    }
                }
            );

            // 获取slug并存入MongoDB(根据实际模型调整)
            const slug = response.data.slug;
            // await FilmModel.updateOne({ _id: req.params._id }, { $push: { episodes: slug } })

            res.json({ msg: "Success add episode", slug });
        } catch (err) {
            console.error(err);
            return res.status(500).json({ msg: err.message });
        }
    },
}

额外注意事项

  • 确保selectVideo是通过<input type="file"/>获取到的File对象,而非其他类型。
  • 需根据Abyss官方文档确认API返回结构,调整response.data.slug的取值路径。
  • 若上传大文件,内存存储可能不足,可改用multer的磁盘存储,读取文件流后再转发。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 00:05:10