使用AWS Amplify Storage类在Expo中上传图片至S3的问题
解决Expo + AWS Amplify上传图片到S3的问题
嘿,我完全懂你的困扰——Expo环境下没法用react-native-fetch-blob,RN又不支持Blob,官方示例都是文本文档,想传图片确实有点卡壳。不过你提到的两个方向都是可行的,我给你拆解下具体实现步骤:
方案一:直接上传Base64到S3(最简单直接)
这是我最推荐的方案,不需要额外搭建服务,利用Amplify Storage的能力就能搞定。核心思路是把图片转成Base64字符串,然后上传时指定正确的Content-Type,S3会自动把它解析成图片文件。
具体步骤+代码示例
- 先搞定权限(结合你给出的代码)
import { Permissions } from 'expo'; import * as ImagePicker from 'expo-image-picker'; // 请求相机相册权限 async function requestPermissions() { const { status } = await Permissions.askAsync(Permissions.CAMERA_ROLL); if (status !== 'granted') { alert('需要获取相册权限才能上传图片哦'); return false; } return true; }
- 选择图片并转为Base64
用Expo的ImagePicker获取图片,同时直接拿到Base64格式的数据:
async function pickImage() { const hasPermission = await requestPermissions(); if (!hasPermission) return; const result = await ImagePicker.launchImageLibraryAsync({ mediaTypes: ImagePicker.MediaTypeOptions.Images, allowsEditing: true, quality: 0.8, // 控制图片质量,减少Base64体积 base64: true, // 关键:开启Base64返回 }); if (!result.cancelled) { await uploadImageToS3(result.base64, result.type); } }
- 用Amplify Storage上传Base64
注意要去掉Base64字符串开头的data:image/jpeg;base64,前缀,然后指定正确的contentType:
import { Storage } from 'aws-amplify'; async function uploadImageToS3(base64Data, mimeType) { // 去掉Base64前缀 const cleanBase64 = base64Data.replace(/^data:image\/\w+;base64,/, ''); try { const key = `uploads/${Date.now()}-image.${mimeType.split('/')[1]}`; // 生成唯一文件名 const result = await Storage.put(key, cleanBase64, { contentType: mimeType, // 重要:指定图片的MIME类型,比如image/jpeg level: 'public', // 根据你的需求选public/private }); console.log('图片上传成功!地址:', result.key); return result.key; } catch (error) { console.error('上传失败:', error); } }
方案二:用Lambda中转上传(适合大图片场景)
如果你的图片很大,Base64会让体积膨胀30%左右,这时候可以用Lambda做中转,Expo把图片的二进制数据(或者Base64)发给Lambda,由Lambda上传到S3。
具体步骤
- 创建Lambda函数(Node.js)
Lambda需要有S3的上传权限,代码示例:
const AWS = require('aws-sdk'); const s3 = new AWS.S3(); exports.handler = async (event) => { try { const { base64Data, fileName, mimeType } = JSON.parse(event.body); const buffer = Buffer.from(base64Data, 'base64'); const params = { Bucket: '你的S3桶名', Key: `uploads/${fileName}`, Body: buffer, ContentType: mimeType, ACL: 'public-read' // 根据需求设置权限 }; await s3.putObject(params).promise(); return { statusCode: 200, body: JSON.stringify({ url: `https://${params.Bucket}.s3.amazonaws.com/${params.Key}` }) }; } catch (error) { return { statusCode: 500, body: JSON.stringify({ error: error.message }) }; } };
- 在Expo中调用Lambda API
把图片转成Base64后,通过API Gateway调用Lambda:
async function uploadViaLambda(base64Data, mimeType) { const fileName = `${Date.now()}-image.${mimeType.split('/')[1]}`; const cleanBase64 = base64Data.replace(/^data:image\/\w+;base64,/, ''); try { const response = await fetch('你的Lambda API Gateway地址', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ base64Data: cleanBase64, fileName, mimeType }) }); const result = await response.json(); console.log('通过Lambda上传成功,地址:', result.url); } catch (error) { console.error('Lambda上传失败:', error); } }
小提示
- 如果用Base64方案,建议压缩图片质量(比如quality设0.7-0.8),减少传输体积
- 确保你的Amplify Storage配置正确,S3桶的CORS规则允许Expo应用访问
- Lambda方案记得给Lambda配置S3的PutObject权限,避免权限错误
内容的提问来源于stack exchange,提问作者cavaleria
相关产品推荐
相关产品推荐

