You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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回调。
解决方案
  1. 移除fetch请求中手动设置的Content-Type头,使用FormData上传时React Native的fetch方法会自动生成正确的multipart/form-data请求头,包含对应的boundary分隔参数。
  2. 持久化存储全局必要参数:将用户授权凭证、接口域名等全局参数存储在AsyncStorage、Zustand/Redux持久化实例中,即使Activity重建也能读取到正确的参数值。
  3. 新增请求响应校验:在解析响应前先判断响应状态是否正常,避免后端返回非200状态码时解析失败抛出异常。
  4. 若仍存在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 01:48:00