Expo(React Native)应用如何正确上传MOV/MP4视频到AWS S3
React Native(Expo)上传MOV视频到S3修复方案
S3本身对上传文件格式没有限制,MOV、MP4都可以正常存储,你上传失败和文件格式无关,核心是代码存在几个逻辑错误:
- 你构造了
ReactNativeFile类型的文件实例newFile,但上传参数的Body字段传的是原始本地URI字符串,AWS SDK无法读取本地文件的二进制内容 - 上传参数的
Key字段直接用了本地文件URI,不是你提前生成的带随机串的新文件名,最终存在S3里的文件会是一串本地设备路径字符串,完全不符合命名规范 - MIME类型设置错误:直接取文件后缀当type值,MOV格式正确的MIME类型是
video/quicktime,MP4是video/mp4,传后缀字符串会导致S3存储的Content-Type字段异常,后续视频无法被浏览器正常识别播放 - 把永久AWS访问密钥硬编码在客户端存在严重安全风险,正式环境直接用会有密钥泄露、资源被恶意操作的隐患
修正后可直接运行的代码
推荐搭配expo-file-system读取本地文件信息,避免路径、类型判断错误:
import AWS from 'aws-sdk'; import { ReactNativeFile } from 'apollo-upload-client'; import * as FileSystem from 'expo-file-system'; const uploadVideoToS3 = async (fileUri) => { try { // 校验本地文件是否存在 const fileInfo = await FileSystem.getInfoAsync(fileUri); if (!fileInfo.exists) throw new Error('选中的视频文件不存在'); // 自动匹配对应格式的MIME类型 const fileExt = fileUri.split('.').pop()?.toLowerCase() || 'mov'; const mimeType = fileExt === 'mov' ? 'video/quicktime' : `video/${fileExt}`; // 生成S3存储用的合法文件名,避免重名覆盖 const dateStr = new Date().toISOString().replace(/[:.]/g, '-'); const randomStr = Math.random().toString(36).slice(2, 7); const s3FileName = `videos/${randomStr}-${dateStr}.${fileExt}`; // 构造SDK可识别的文件实例 const uploadTarget = new ReactNativeFile({ uri: fileUri, name: s3FileName.split('/').pop(), type: mimeType, }); // 初始化S3客户端 AWS.config.update({ region: 'eu-north-1', credentials: new AWS.Credentials(AWS_S3_ACCESS_KEY, AWS_S3_SECRET_KEY), }); const s3Instance = new AWS.S3(); *注意:正式环境请替换为后端签发的STS临时凭证,禁止硬编码永久AK/SK到客户端代码中* // 配置上传参数 const uploadParams = { Bucket: 'bucket-name', Key: s3FileName, Body: uploadTarget, ACL: 'public-read', ContentType: mimeType, }; *该字段必须显式指定,否则S3会默认将文件标记为binary/octet-stream,导致后续视频无法正常播放* // 执行分片上传,适配大体积视频 const uploadRes = await s3Instance.upload(uploadParams, { partSize: 10 * 1024 * 1024, // 单分片10MB,支持断点续传 queueSize: 2, }).promise(); console.log('上传成功,文件地址:', uploadRes.Location); return uploadRes.Location; } catch (err) { console.log('上传失败:', err.message); throw err; } };
后续注意事项
- MOV格式不需要提前转码即可上传到S3,如果后续需要多端兼容播放,可以在上传完成后触发AWS MediaConvert任务转码为H.264编码的MP4格式,不影响上传流程
- iOS端如果ImagePicker返回的是
ph://开头的相册URI,调用选择器时加上allowsEditing: false参数,会自动返回可直接读取的本地file路径,不需要额外做相册权限适配 - CloudFront配置要点:等上传功能调试通后,源站选择对应S3桶,开启OAC源站访问控制,关闭S3桶的公网访问权限,所有流量走CloudFront;缓存策略放行
Range请求头,支持视频边下边播 - 安全提示:正式上线前一定要把客户端硬编码的永久密钥替换成后端签发的STS临时凭证,给临时凭证设置最小上传权限和15分钟以内的过期时间,避免密钥泄露产生高额账单
内容的提问来源于stack exchange,提问作者jacob
相关产品推荐
相关产品推荐

