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

React Native中使用@aws-sdk/lib-storage分片上传S3遇错求助

在React Native中使用@aws-sdk/lib-storage实现S3文件上传的可行方案

能成功实现,但需要先解决React Native与Web/Node.js环境的API差异问题,以下是具体解决思路:

1. 补全缺失的环境API

React Native默认没有Buffer、ReadableStream这类Web/Node环境的核心API,这是你遇到"ReadableStream is not defined""Buffer is not defined"错误的直接原因。可以通过polyfill来补全:

  • 安装依赖:
    npm install buffer readable-stream react-native-polyfill-globals
    
  • 在项目入口文件(如App.js)顶部导入polyfill:
    // 全局补全所有缺失API
    import 'react-native-polyfill-globals/globals';
    
    // 或者单独补全需要的API
    import { Buffer } from 'buffer';
    global.Buffer = Buffer;
    import { ReadableStream } from 'readable-stream';
    global.ReadableStream = ReadableStream;
    
  • 若遇到Metro打包报错,需在metro.config.js中添加对polyfill包的支持:
    module.exports = {
      resolver: {
        extraNodeModules: require('node-libs-react-native'),
      },
    };
    
    (需提前安装node-libs-react-native)

2. 适配文件流格式

RNFetchBlob返回的流与AWS SDK要求的Web标准ReadableStream不兼容,需要手动转换:

const convertToReadableStream = (rnStream) => {
  return new ReadableStream({
    start(controller) {
      rnStream.onData(chunk => {
        // 若使用base64编码,需转换为Uint8Array
        const uint8Array = Uint8Array.from(atob(chunk), c => c.charCodeAt(0));
        controller.enqueue(uint8Array);
      });
      rnStream.onEnd(() => controller.close());
      rnStream.onError(err => controller.error(err));
    },
    cancel() {
      rnStream.close();
    }
  });
};

// 修改你的readFileAsStream方法
const readFileAsStream = async (fileUri, encoding = "base64", bufferSize = 4095) => {
  return new Promise((resolve, reject) => {
    RNFetchBlob.fs
      .readStream(fileUri, encoding, bufferSize)
      .then(ifstream => {
        ifstream.open();
        resolve(convertToReadableStream(ifstream));
      })
      .catch(err => reject(err));
  });
};

3. 简化方案:使用Buffer直接上传

如果对流转换感到繁琐,可以直接将文件读取为Buffer后上传,避免流适配问题:

import RNFS from 'react-native-fs';

const getFileBuffer = async (fileUri) => {
  const base64Content = await RNFS.readFile(fileUri, 'base64');
  return Buffer.from(base64Content, 'base64');
};

// 上传逻辑
const uploadToS3 = async (fileUri, key) => {
  try {
    const buffer = await getFileBuffer(fileUri);
    const upload = new Upload({
      client: s3,
      params: {
        Bucket: S3_BUCKET_NAME,
        Key: key,
        Body: buffer
      },
      partSize: 1024 * 1024 * 5
    });

    upload.on("httpUploadProgress", progress => {
      console.log(`上传进度: ${(progress.loaded / progress.total * 100).toFixed(2)}%`);
    });

    await upload.done();
    console.log("上传完成");
  } catch (err) {
    console.error("上传失败:", err);
  }
};

4. 更省心的替代方案:使用AWS Amplify

如果不想手动处理环境适配,推荐使用aws-amplify/storage包,它已完全适配React Native,封装了S3上传的所有细节:

import { Storage } from 'aws-amplify';

const uploadWithAmplify = async (fileUri, key) => {
  try {
    const result = await Storage.put(key, fileUri, {
      contentType: 'image/jpeg', // 根据文件类型修改
      progressCallback: (progress) => {
        console.log(`上传进度: ${(progress.loaded / progress.total * 100).toFixed(2)}%`);
      }
    });
    console.log("上传完成,文件地址:", result.key);
    return result;
  } catch (err) {
    console.error("上传失败:", err);
  }
};

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 09:07:05