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

React Native安卓端通过Axios传图片至Node.js后端,Multer无法识别文件

React Native(安卓)上传图片至Express后端,Multer无法识别文件

我正尝试从React Native前端(安卓手机)向Node.js/Express后端发送图片,图片需经Multer处理后上传至Cloudinary(此步骤与问题无关)。用Postman测试一切正常,但通过Axios(也试过fetch)发起POST请求时失败,Multer识别不到请求里的文件。

前端代码

const uploadProfileImage = async ()=>{
        const formData = new FormData();
        //console.log(profileImage);
        const image = {
            uri: profileImage,
            type: mime.getType(profileImage),
            name: new Date() + "_pfp",
          } as any
        formData.append('pfp', {
            uri: profileImage,
            type: mime.getType(profileImage),
            name: new Date() + "_pfp",
        });
        try {
            const res = await client.post('/upload-pfp', formData, {headers:{
                Accept: 'application/json',
                'Content-Type': 'multipart/form-data',
                authorization: 'JWT ...',
            }});
            console.log(res.data);
        } catch (error) {
            console.error('Upload failed:', {
                message: error.message,
                status: error.response?.status,
                data: error.response?.data
              });
        }

    }

后端POST请求处理器

router.post('/upload-pfp', isAuth, uploads.single('pfp'), uploadPfp)

Multer配置

const multer = require('multer');

const storage = multer.diskStorage({});

const fileFilter = (req, file, cb)=>{
    console.log("first")
    if(file.mimetype.startsWith('image')){
        cb(null, true);
    }else{
        cb('Invalid image file', false);
    }
}

const uploads = multer({storage, fileFilter})

授权中间件(供参考)

exports.isAuth = async(req, res, next)=>{
    if(req.headers && req.headers.authorization){
        const token = req.headers.authorization.split(' ')[1];
        try {
            const decode = jwt.verify(token, process.env.JWT_SECRET);
        
            const user = await User.findById(decode.userId);
            if(!user){
                return res.json({success: false, message: "Unauthorized access"});
            }
            req.user = user;
            next();
        } catch (error) {
            if(error.name == 'JsonWebTokenError'){
                return res.json({success: false, message: "Unauthorized access"});
            }
            if(error.name == 'TokenExpiredError'){
                return res.json({success: false, message: "Session expired, try signing in"});
            }
            res.json({success: false, message: "Internal server error"});
        }
        
    } else {
        res.json({success: false, message: "Unauthorized access"})
    }
}

解决办法

1. 修复React Native FormData文件格式问题

React Native的FormData对文件对象的要求和Web端不同,不能直接传普通对象,且不要手动设置Content-Type头(Axios会自动根据FormData生成正确的multipart边界)。另外安卓端的uri需要去掉file://前缀:

修改前端代码:

import { Platform } from 'react-native';

const uploadProfileImage = async ()=>{
    const formData = new FormData();
    // 处理安卓端uri格式
    const fixedUri = Platform.OS === 'android' ? profileImage.replace('file://', '') : profileImage;
    formData.append('pfp', {
        uri: fixedUri,
        type: mime.getType(fixedUri) || 'image/jpeg', // 兜底默认图片类型
        name: `${Date.now()}_pfp.jpg`
    });
    try {
        const res = await client.post('/upload-pfp', formData, {
            headers: {
                authorization: 'JWT ...',
                // 移除手动设置的Content-Type
            }
        });
        console.log(res.data);
    } catch (error) {
        console.error('Upload failed:', {
            message: error.message,
            status: error.response?.status,
            data: error.response?.data
        });
    }
}

2. 后端加日志排查

在isAuth中间件末尾或uploadPfp函数开头添加日志,确认请求是否携带文件:

// 在isAuth的next()前添加
console.log('请求体:', req.body);
console.log('接收的文件:', req.file);

3. 确认安卓权限配置

检查AndroidManifest.xml是否添加了图片读取权限:

<!-- Android 12及以下 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<!-- Android 13+ -->
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />

4. 兜底MIME类型

如果mime.getType(profileImage)返回undefined,会触发Multer的fileFilter拒绝文件,所以必须设置兜底值,比如上面代码中的'image/jpeg'。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 13:36:12