在React Native中使用@aws-sdk/lib-storage分段上传到S3

问题描述 投票:0回答:1

我有以下代码;

 const readFileAsStream = async (
        fileUri,
        encoding = "base64",
        bufferSize = 4095
    ) => {
        return new Promise((resolve, reject) => {
            RNFetchBlob.fs
                .readStream(fileUri, encoding, bufferSize)
                .then(ifstream => {
                    ifstream.open();
                    resolve(ifstream);
                })
                .catch(err => {
                    reject(err);
                });
        });
    };

    // usage example
    readFileAsStream(fileUri)
        .then(stream => {
            const upload = new Upload({
                client: s3,
                params: {
                    Bucket: S3_BUCKET_NAME,
                    Key: key,
                    Body: stream
                },
                partSize: 1024 * 1024 * 5 // minimum part size allowed by S3
            });
            upload.on("httpUploadProgress", progress => {
                console.log(progress);
            });
            upload.done();
        })
        .catch(err => {
            console.log(err);
        });

第一部分旨在将本地文件作为流读取,第二部分使用 @aws-sdk/lib-storage 包将其上传到 S3。

我尝试将文件转换为缓冲区、blob 或流,但根据格式,我收到各种错误,例如“ReadableStream 未定义”、“Buffer 未定义”等。

这个包更多地用于网络,所以这里假设这些是包错误。有人在 React Native 中使用这个包将文件上传到 AWS S3 吗?

reactjs amazon-web-services react-native amazon-s3 mobile
1个回答
0
投票

有点晚了,但希望其他遇到此问题的人可以度过愉快的时光。 我最近尝试从 RN 到 S3 上传视频,也遇到了一些麻烦,这是我的解决方案,我已经测试过它可以在 Android 和 APK 上运行。还没上iOS。

import { S3Client, CreateMultipartUploadCommand, UploadPartCommand, Complet eMultipartUploadCommand, AbortMultipartUploadCommand } from "@aws-sdk/client-s3"; import { Buffer } from 'buffer'; import 'react-native-url-polyfill/auto'; import { ReadableStream } from 'web-streams-polyfill'; import 'react-native-get-random-values'; import RNFS from 'react-native-fs'; import moment from "moment"; declare global { var ReadableStream: ReadableStream } globalThis.ReadableStream = ReadableStream const s3Client = new S3Client({ region: REGION, credentials: { accessKeyId: supersecrets.accesskey, secretAccessKey: supersecrets.secretkey, // mustn't have special characters (dont ask why) } }); export const main = async (path: string) => { const key = `${moment().utcOffset(0).format('YYYY-MM-DD HH:mm:ss')}.mov`; // your filename const partSize = 5 * 1024 * 1024; // multipart needs parts of 5mb for all but the last part const fileData = await RNFS.readFile(path, 'ascii'); const buffer = Buffer.from(fileData, 'ascii'); const totalParts = Math.ceil(buffer.length / partSize) let uploadId; try { const multipartUpload = await s3Client.send( new CreateMultipartUploadCommand({ Bucket: bucketName, Key: key, }), ); uploadId = multipartUpload.UploadId; const uploadPromises = []; // Upload each part. for (let i = 0; i < totalParts; i++) { const start = i * partSize; const end = start + partSize; uploadPromises.push( s3Client .send( new UploadPartCommand({ Bucket: bucketName, Key: key, UploadId: uploadId, Body: buffer.subarray(start, end), PartNumber: i + 1, }), ) .then((d) => { return d; }), ); } const uploadResults = await Promise.all(uploadPromises); return await s3Client.send( new CompleteMultipartUploadCommand({ Bucket: bucketName, Key: key, UploadId: uploadId, MultipartUpload: { Parts: uploadResults.map(({ ETag }, i) => ({ ETag, PartNumber: i + 1, })), }, }), ); } catch (err) { console.error(err); if (uploadId) { const abortCommand = new AbortMultipartUploadCommand({ Bucket: bucketName, Key: key, UploadId: uploadId, }); await s3Client.send(abortCommand); } } };

关于流程的一些说明。您将需要 
react-native-url-polyfill/auto

react-native-get-random-valuesweb-streams-polyfill。因为(我认为)sdk 需要能够动态生成值(上传 id 和 url),但默认情况下不附带它。 也许只是我开发中的一个问题,但你的密钥也不能有特殊字符

/ +

等。再次不确定为什么这是一个问题,但它是......

我使用了 ASCII 编码,因为 base64 已损坏,所以请尝试一下最适合你的 :D

AWS 文档

其中一半摘自其中

© www.soinside.com 2019 - 2024. All rights reserved.