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
相关产品推荐
相关产品推荐

