React Native使用expo-image-picker上传图片Android端POST请求失败求助
报错原因
- 请求头配置错误:上传FormData格式的文件时,代码手动指定了
Content-Type: application/json,该类型和请求体格式完全不匹配。FormData上传需要的是带boundary分隔符的multipart/form-data类型头,安卓端网络层对请求头校验更严格,会直接抛出解析错误,iOS端对这类错误的兼容性更强所以运行正常。 - Activity重建后上下文丢失:安卓系统内存不足时,调起图片选择/裁剪页面会触发原MainActivity销毁,裁剪完成回到应用后Activity重建,若
bearer授权凭证、API接口域名等参数存储在组件临时state/变量中,重建后参数会丢失,导致请求参数异常直接进入catch回调。
解决方案
- 移除fetch请求中手动设置的
Content-Type头,使用FormData上传时React Native的fetch方法会自动生成正确的multipart/form-data请求头,包含对应的boundary分隔参数。 - 持久化存储全局必要参数:将用户授权凭证、接口域名等全局参数存储在AsyncStorage、Zustand/Redux持久化实例中,即使Activity重建也能读取到正确的参数值。
- 新增请求响应校验:在解析响应前先判断响应状态是否正常,避免后端返回非200状态码时解析失败抛出异常。
- 若仍存在uri读取异常,可使用expo-file-system将返回的content协议uri转成本地文件路径再上传,expo-image-picker返回的uri默认带有临时读取权限,无需额外申请存储权限。
修复后参考代码
import AsyncStorage from '@react-native-async-storage/async-storage'; // 图片选择逻辑 const prepareResult = await ImagePicker.launchImageLibraryAsync({ quality: 0.5, capture: true, aspect: [4, 3], allowsEditing: true, allowsMultipleSelection: false, mediaTypes: ImagePicker.MediaTypeOptions.Images, }); const androidResult = await ImagePicker.getPendingResultAsync(); const result = androidResult?.length ? androidResult[0] : prepareResult; if (!result.cancelled) { const localUri = result.uri; const filename = localUri.split("/").pop(); const match = filename ? /\.(\w+)$/.exec(filename) : ""; const type = match ? `image/${match[1]}` : `image`; const formData = new FormData(); formData.append("file", { uri: localUri, name: filename, type }); // 从持久化存储读取必要参数,避免Activity重建后参数丢失 const bearer = await AsyncStorage.getItem('user_token'); const API = await AsyncStorage.getItem('api_base_url'); fetch(`${API}/uploadAvatar`, { method: "POST", headers: { Authorization: bearer, "X-Requested-With": "XMLHttpRequest", // 移除手动设置的Content-Type,由fetch自动生成 }, body: formData, }) .then((response) => { // 新增响应状态校验 if (!response.ok) throw new Error(`请求失败,状态码:${response.status}`); return response.json(); }) .then((json) => { setImage(json.file); }) .catch((err) => { console.log("头像上传错误:", err); Alert.alert("头像上传失败,请稍后重试"); }); }
内容的提问来源于stack exchange,提问作者Reacting
相关产品推荐
相关产品推荐

