Expo安卓端上传M4A音频至服务器提示非音频文件问题
问题原因分析
- Android端URI格式不兼容:Expo在Android上返回的录音文件URI带有
file://前缀,但FormData在Android环境下需要的是本地文件的绝对路径而非带scheme的URI,保留前缀会导致无法正确读取文件内容,服务器收到异常数据后判定不是音频文件。 - MIME类型匹配问题:代码中指定的
audio/m4a是iOS端标准MIME类型,但Android上Expo录制的M4A文件实际对应的标准MIME类型为audio/mp4,服务器的文件类型校验逻辑可能对MIME类型的匹配要求更严格。
解决方案
- 恢复Android端URI前缀处理逻辑
取消注释代码中移除file://前缀的逻辑,确保上传的是正确的本地文件路径:
let convertedUri = uri; if (Platform.OS === 'android') { // Android环境下需移除file://前缀,使用绝对路径 convertedUri = uri.replace('file://', ''); }
- 适配跨平台MIME类型
根据系统平台设置对应的MIME类型,避免服务器校验不通过:
formData.append('session_audio', { uri: convertedUri, type: Platform.OS === 'android' ? 'audio/mp4' : 'audio/m4a', name: `recording_${Date.now()}.m4a`, // 用时间戳生成唯一文件名,避免重复冲突 });
- 上传前验证文件有效性(可选)
使用Expo的FileSystem模块检查文件是否存在,避免上传无效路径:
import * as FileSystem from 'expo-file-system'; const handleSubmit = async () => { let convertedUri = uri; if (Platform.OS === 'android') { convertedUri = uri.replace('file://', ''); } // 检查文件是否存在且为有效文件 const fileInfo = await FileSystem.getInfoAsync(convertedUri); if (!fileInfo.exists || !fileInfo.isFile) { console.error('录音文件不存在或路径无效'); return; } const formData = new FormData(); formData.append('session_name', textInputValue); formData.append('session_audio', { uri: convertedUri, type: Platform.OS === 'android' ? 'audio/mp4' : 'audio/m4a', name: `recording_${Date.now()}.m4a`, }); mutate({ assets: formData }); // 重置状态逻辑... };
- 确认服务器校验规则
如果上述调整后仍有问题,需确认服务器是仅通过MIME类型判断文件,还是会校验文件头(magic number)。可使用ffmpeg工具检查Android端录制文件的编码格式:
ffmpeg -i 本地录音文件路径
若文件编码为标准M4A格式,可要求服务器放宽MIME类型匹配规则,同时支持audio/mp4和audio/m4a。
内容的提问来源于stack exchange,提问作者Waleed Taher
相关产品推荐
相关产品推荐

