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

React Native+Express上传图片返回200但文件未保存问题排查

问题排查与修复

你收到200响应但文件未保存,是前后端代码共存在多处语法、配置错误导致的,逐个修复即可:

后端(Multer端)错误点

  • 配置项拼写错误:磁盘存储配置的destintion为拼写错误,正确字段名是destination,Multer无法识别错误字段,不会执行文件写入逻辑
  • 文件名生成逻辑错误:callback(null, Date.now() = path.extname(file.originalname))中错误使用赋值运算符=拼接文件后缀,应该用字符串拼接符+;另外使用path.extname前需要先引入Node内置的path模块
  • 路由方法不匹配:上传是POST请求,不应该用app.use注册接口,要改用app.post
  • 路径兼容问题:存储路径avatars写相对路径容易出现路径匹配错误,建议结合__dirname写绝对路径,且Multer不会自动创建不存在的目录,需要提前手动创建avatars文件夹,或启动时通过fs模块自动创建。

修复后的后端参考代码:

const express = require('express');
const multer = require('multer');
const path = require('path');
const fs = require('fs');

const app = express();
// 自动创建avatars存储目录
const avatarDir = path.join(__dirname, 'avatars');
if (!fs.existsSync(avatarDir)) {
  fs.mkdirSync(avatarDir, { recursive: true });
}

const storage = multer.diskStorage({
  destination: (req, file, callback) => {
    callback(null, avatarDir)
  },
  filename: (req, file, callback) => {
      callback(null, Date.now() + path.extname(file.originalname));
  }
});

const upload = multer({storage: storage});

// 改用app.post接收POST上传请求
app.post("/uploadAvatar", upload.single("avatar"), (req, res) => {
  res.status(200).json("Image enregistrée !")
})

app.listen(8000, () => console.log('服务启动在8000端口'))

前端(React Native端)错误点

  • 缺少取消选择判断:调用DocumentPicker后要先判断用户是否取消了选择,否则用户点取消后拿不到uri会直接抛错
  • FormData传参冗余:append文件对象时不需要额外加file: result.file字段,只需要传uri、type、name三个属性即可
  • 请求头配置错误:不要手动设置Content-Type: multipart/form-data,multipart/form-data请求需要自动携带随机生成的boundary分隔符,手动写死请求头会导致boundary丢失,后端无法解析到上传的文件
  • 冗余配置:自定义的transformRequest完全多余,Axios识别到FormData类型的请求体时会自动做格式转换,直接删掉即可
  • 版本兼容问题:Expo SDK 48以上版本的DocumentPicker返回结构调整为{ canceled: boolean, assets: [...] }格式,要从assets数组里取文件属性,直接取顶层的uri、fileName会拿到undefined。

修复后的前端参考代码:

import * as DocumentPicker from 'expo-document-picker';
import axios from 'axios';

const pickPicture = async () => {
  let result = await DocumentPicker.getDocumentAsync({
    type: 'image/*' // 可限制仅选择图片文件
  });
  // 用户取消选择直接终止流程
  if (result.canceled) {
    return;
  }
  // 兼容新旧版本DocumentPicker返回结构
  const fileAsset = result.assets ? result.assets[0] : result;
  console.log(fileAsset);

  const data = new FormData();
  data.append("avatar", {
    uri: fileAsset.uri,
    type: fileAsset.mimeType || fileAsset.type,
    name: fileAsset.name || fileAsset.fileName,
  });

  axios
    .post(
      `http://localhost:8000/uploadAvatar`,
      data,
      {
        withCredentials: true,
        // 不要手动设置Content-Type,让Axios自动生成带boundary的合法请求头
      }
    )
    .catch(function (error) {
      console.log('上传失败', error);
    })
    .then(function (res) {
      console.log('上传成功', res);
    });
}

补充:如果用安卓本地模拟器调试,前端请求地址不要写localhost,要换成10.0.2.2才能访问到电脑本地启动的Node服务,iOS模拟器和web调试可正常使用localhost。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 10:36:24