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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 05:27:21