Expo React Native安卓端Fetch Multipart图片上传失败,iOS正常
安卓端Expo React Native Fetch上传FormData图片失败的解决方案
针对你遇到的安卓端图片上传报TypeError: Network request failed但iOS正常的问题,以下是几个常见原因和对应的解决步骤:
1. 安卓URI格式兼容性问题
Expo中安卓设备获取的图片URI通常是content://开头的,Fetch在处理这类URI时可能存在兼容性问题,导致无法正确读取文件内容。
解决方法:
使用expo-file-system将图片复制到缓存目录,使用缓存目录的URI进行上传:
import * as FileSystem from 'expo-file-system'; import { Platform } from 'react-native'; const callUploadApi = async () => { try { // 处理安卓URI let uploadUri = imgUri; if (Platform.OS === 'android' && uploadUri.startsWith('content://')) { // 复制图片到缓存目录 const fileName = imgUri.split('/').pop(); const cacheUri = FileSystem.cacheDirectory + fileName; await FileSystem.copyAsync({ from: imgUri, to: cacheUri }); uploadUri = cacheUri; } const imageType = uploadUri.endsWith(".jpg") ? "image/jpeg" : uploadUri.endsWith(".png") ? "image/png" : uploadUri.endsWith(".gif") ? "image/gif" : "image/jpeg"; const formdata = new FormData(); formdata.append("file", { uri: Platform.OS === 'android' ? uploadUri.replace('file://', '') : uploadUri, // 安卓去掉file://前缀 type: imageType, name: uploadUri.split("/").pop(), }); const requestOptions = { method: "POST", body: formdata, redirect: "follow", }; const response = await fetch(`${SERVER_URL}/api/upload`, requestOptions); if (!response.ok) { const errorResponse = await response.json(); throw errorResponse; } const result = await response.json(); const { fileUrl } = result.data; setImgUrl(fileUrl); Alert.alert("Upload Success", "Image uploaded successfully"); } catch (error) { console.error(error); Alert.alert("Upload Failed", "Image upload failed"); } };
2. 动态权限未正确申请
虽然你检查了app.json中的权限,但安卓13+需要动态申请READ_MEDIA_IMAGES权限,旧版本需要READ_EXTERNAL_STORAGE,仅在配置文件中声明权限无法完成授权流程。
解决方法:
在调用图片选择或上传接口前,动态申请媒体权限:
import * as ImagePicker from 'expo-image-picker'; import { Alert } from 'react-native'; const requestMediaPermission = async () => { const { status } = await ImagePicker.requestMediaLibraryPermissionsAsync(); if (status !== 'granted') { Alert.alert('权限不足', '请授予应用访问媒体库的权限,否则无法上传图片'); return false; } return true; }; // 在调用callUploadApi前先执行权限检查 const handleUpload = async () => { const hasPermission = await requestMediaPermission(); if (hasPermission) { await callUploadApi(); } };
3. 服务器端对安卓请求的兼容性问题
安卓上传的FormData请求头或文件名格式可能与iOS略有差异,导致服务器无法解析:
- 检查服务器日志,确认安卓请求是否到达服务器,若到达,查看是否有解析Multipart数据的错误
- 尝试将文件名改为纯英文格式,避免中文或特殊字符:
name: `upload_image.${imageType.split('/')[1]}` // 替换原name字段 - 确认服务器的
client_max_body_size(如Nginx配置)足够大,避免因图片过大被拦截
4. Fetch请求头的隐性问题
虽然Fetch会自动为FormData设置multipart/form-data头,但安卓端有时需要显式添加Accept头,确保服务器返回正确格式的响应:
const requestOptions = { method: "POST", body: formdata, headers: { Accept: 'application/json', }, redirect: "follow", };
注意:不要手动设置Content-Type为multipart/form-data,否则会丢失自动生成的boundary参数,导致服务器无法解析表单数据。
内容的提问来源于stack exchange,提问作者Pragyan Boruah
相关产品推荐
相关产品推荐

