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

Expo环境下React Native图片上传至GCS失败问题排查

Expo环境下React Native上传GCS失败的配置与代码调整方案

问题描述

原有iOS平台React Native应用可正常上传图片到Google Cloud Storage(GCS),但将相同代码迁移到新Expo项目(React Native 0.74.5、Expo 51.0.28)后,iOS和Android模拟器均上传失败,返回400网络错误且无详细信息。相关代码如下:

const formData = new FormData();

Object.entries({
  ...data.imageFields, // 包含从后端API获取的key、policy、x-goog-algorithm、x-goog-credential、x-goog-signature、x-goog-meta-source字段
  file: {
    uri: curPhoto.path, // 示例路径:"/Users/username/Library/Developer/CoreSimulator/Devices/9EDEBECD-B892-4D34-9142-C559B5A32416/data/Containers/Data/Application/2879C35B-DE2C-439F-8AF4-AA53D6D0C380/Library/Caches/EC6FD27A-A8E6-4344-9580-191130EE7045.jpg"
    name: imageId, // 示例ID:"9af64c5f-e0d7-45cf-88a0-4635am46d16e"
    type: curPhoto.mimeType, // 示例类型:"image/jpeg"
  },
}).forEach(([key, value]) => {
  formData.append(key, value as string | Blob);
});

const URL = "https://storage.googleapis.com/my-bucket/";
const result = await fetch(URL, {
  method: "POST",
  body: formData,
  headers: {  // 试过添加或移除这些header都无效
    Accept: "application/json",
    "Content-Type": "multipart/form-data",
  },
});

// 返回400网络错误,无详细信息

必要配置与代码调整

1. 修正图片URI格式

Expo在iOS模拟器上获取的图片路径是本地文件路径,GCS上传需要file://前缀的URI,需针对iOS平台调整:

file: {
  uri: Platform.OS === 'ios' ? `file://${curPhoto.path}` : curPhoto.path,
  name: imageId,
  type: curPhoto.mimeType,
}

2. 移除手动设置的Content-Type头

手动指定multipart/form-data会覆盖fetch自动生成的带boundary的Content-Type,导致GCS无法解析表单,直接删除该字段:

const result = await fetch(URL, {
  method: "POST",
  body: formData,
  headers: {
    Accept: "application/json",
    // 移除"Content-Type": "multipart/form-data"
  },
});

3. 配置Expo网络权限(物理设备适配)

如果后续测试物理设备,需在app.json中添加网络访问配置:

{
  "expo": {
    "ios": {
      "infoPlist": {
        "NSAppTransportSecurity": {
          "NSExceptionDomains": {
            "storage.googleapis.com": {
              "NSIncludesSubdomains": true,
              "NSAllowsArbitraryLoads": true
            }
          }
        }
      }
    },
    "android": {
      "usesCleartextTraffic": true,
      "permissions": ["INTERNET"]
    }
  }
}

模拟器通常无需额外权限,物理设备需确保网络访问正常。

4. 校验FormData字段完整性

上传前打印FormData内容,确认data.imageFields中的policy、signature等关键字段未被篡改:

// 调试用:打印FormData所有键值对
for (let pair of formData.entries()) {
  console.log(`${pair[0]}: ${pair[1]}`);
}

内容的提问来源于stack exchange,提问作者YepNamesJames

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 20:22:42