如何使用expo-image-picker将iOS端文件上传到Cloudinary?
React Native Expo 直传Cloudinary 400错误+进度监听解决方案
核心问题原因
你遇到的400错误基本都是本地资源格式不对、FormData构造不规范导致的:
- 从相册拿到的
file://开头的本地URI直接作为字符串提交,会被Cloudinary识别为无效URL - React Native环境下的FormData和Web端构造规则不同,缺参数会触发
缺少file参数报错
实现方案(无需额外依赖、支持进度监听、支持签名)
因为要获取上传进度,直接使用React Native原生支持的XMLHttpRequest即可,不需要用fetch。
步骤1:构造FormData
拿到相册选中的资源后,按以下格式构造file字段,这是解决400错误的核心:
// 假设你用expo-image-picker拿到的选中资源为pickedAsset const formData = new FormData(); // 通用参数,测试用unsigned上传预设,签名上传可替换为对应参数 formData.append('upload_preset', '你在Cloudinary后台创建的上传预设名'); formData.append('folder', '可选,指定上传到Cloudinary的文件夹'); // 核心:构造file字段,*三个参数缺一不可* formData.append('file', { uri: pickedAsset.uri, type: pickedAsset.type === 'image' ? 'image/jpeg' : pickedAsset.mimeType, name: pickedAsset.fileName || `upload_${Date.now()}.jpg` }); // 后续要做签名上传的话,追加以下参数即可,签名按Cloudinary规则生成 // formData.append('api_key', '你的Cloudinary API Key'); // formData.append('timestamp', 生成签名用的时间戳); // formData.append('signature', 预先生成的签名值);
步骤2:带进度监听的上传请求
const xhr = new XMLHttpRequest(); // 上传地址替换成你自己的cloud name,传视频就把末尾的image/upload改成video/upload xhr.open('POST', 'https://api.cloudinary.com/v1_1/你的Cloudinary cloud name/image/upload'); // 监听上传进度 xhr.upload.onprogress = (event) => { if (event.lengthComputable) { const progressPercent = Math.round((event.loaded / event.total) * 100); // 这里直接更新你的进度指示器状态即可 console.log(`上传进度:${progressPercent}%`); } }; // 请求完成回调 xhr.onload = () => { if (xhr.status === 200) { const response = JSON.parse(xhr.responseText); // 上传成功,response里有资源的访问地址等信息 console.log('上传成功', response.secure_url); } else { // 打印错误信息方便排查 console.log('上传失败', xhr.status, xhr.responseText); } }; xhr.onerror = (err) => { console.log('请求错误', err); }; // 发送请求 xhr.send(formData);
常见400错误排查点
- 确认上传地址里的cloud name拼写完全正确
- 确认
file字段的三个属性都正确传入,iOS的file://前缀不需要额外删除 - 用unsigned上传预设测试时,确认Cloudinary后台已经开启该预设的unsigned上传权限
- 签名上传时,确认签名生成规则和参数顺序符合要求,timestamp没有过期
内容的提问来源于stack exchange,提问作者Michel Floyd
相关产品推荐
相关产品推荐

