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

React-Native(Expo)图片经Node.js转存S3失败问题求助

解决React-Native(Expo)图片通过Node.js转存AWS S3时的乱码问题

问题根源

乱码问题来自三个核心错误:

  1. 前端错误设置Content-Type: application/json请求头,但实际发送的是FormData格式数据,导致后端无法正确解析
  2. 前端FormData中的文件对象缺少必要属性(文件名、真实MIME类型)
  3. 后端未配置文件上传解析器,无法处理multipart/form-data格式的请求

前端代码修复

修改点:

  • 移除手动设置的Content-Type头,让fetch自动生成正确的multipart/form-data请求头
  • 从ImagePicker返回结果中获取真实的文件MIME类型,替换硬编码的'image'
  • 为上传文件添加自定义文件名(避免重名)
  • 给fetch添加await,确保正确处理响应

修改后的完整代码:

const [imageAsset, setImageAsset] = useState(null);
const pickImage = async () => {
  let result = await ImagePicker.launchImageLibraryAsync({
    mediaTypes: ImagePicker.MediaTypeOptions.All,
    allowsEditing: true,
    aspect: [4, 3],
    quality: 1,
  });
  if (!result.canceled) {
    setImageAsset(result.assets[0]); // 保存完整的asset对象,方便获取type/uri
  }
};

// 抽离上传逻辑到单独函数,避免在渲染阶段执行
const uploadImage = async () => {
  if (!imageAsset) return;
  
  try {
    const formdata = new FormData()
    formdata.append('name', 'avatar');
    
    // 生成唯一文件名:时间戳+原始文件后缀
    const fileExt = imageAsset.uri.split('.').pop();
    const fileName = `${Date.now()}.${fileExt}`;
    
    formdata.append('fileData', {
      uri: imageAsset.uri,
      type: imageAsset.type, // 使用ImagePicker返回的真实MIME类型
      name: fileName, // 必须添加文件名属性
    });
    
    const res = await fetch('http://172.20.10.2:4000/upload', {
      method: 'POST',
      headers: {
        Accept: 'application/json',
        // 移除手动设置的Content-Type,让fetch自动处理
      },
      body: formdata,
    });
    
    const responseData = await res.json();
    console.log('上传成功,文件地址:', responseData.location);
  } catch (e) {
    console.error('上传失败:', e);
  }
};

// 示例:通过按钮点击触发上传
// <Button title="上传图片" onPress={uploadImage} />

后端代码修复

修改点:

  • 安装multer依赖,用于解析文件上传请求
  • 配置multer内存存储,直接将文件内容传给S3
  • 修改/upload路由,使用multer中间件获取文件
  • 调整uploadFile函数,适配multer返回的文件对象

步骤1:安装依赖

npm install multer

步骤2:修改后端代码

const multer = require('multer');
const AWS = require('aws-sdk');

// 初始化AWS S3客户端(确保已配置凭证:环境变量或AWS配置文件)
const client = new AWS.S3();

// 配置multer使用内存存储,避免生成本地临时文件
const storage = multer.memoryStorage();
const uploadMiddleware = multer({ storage: storage });

async function uploadFile(file) {
  const params = {
    Bucket: "XXX", // 替换为你的S3桶名
    Key: file.originalname, // 使用前端传来的文件名,也可自定义
    Body: file.buffer, // multer存在内存中的文件二进制内容
    ACL: "public-read",
    ContentType: file.mimetype, // 设置正确的文件MIME类型
  };
  const data = await client.upload(params).promise();
  return data.Location; // 返回S3文件的公开访问地址
}

// 使用multer的single中间件,处理名为fileData的文件字段
app.post("/upload", uploadMiddleware.single('fileData'), async (req, res) => {
  try {
    // req.file是multer解析后的文件对象
    const fileLocation = await uploadFile(req.file);
    return res.status(200).json({ location: fileLocation });
  } catch (error) {
    console.error('S3上传失败:', error);
    return res.status(500).json({ error: '上传失败' });
  }
});

关键注意事项

  • React Native上传FormData时,文件对象必须包含uri、type、name三个属性,缺一不可
  • 后端使用multer内存存储模式,无需在服务器本地保存文件,直接将二进制数据传给S3,提升效率
  • 确保AWS客户端拥有S3桶的上传权限(可通过IAM角色或环境变量AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY配置)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 09:40:28