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

Expo React Native调用iNaturalist API时图片处理请求失败问题

解决Expo React Native调用iNaturalist API的动物识别问题

核心问题拆解

iNaturalist的图片识别接口要求严格的multipart/form-data请求格式,而Expo环境下的本地文件URI(file://开头)无法直接被外部API识别,转Blob时容易因Expo文件系统的沙箱特性出错,这是导致"Network request failed"和422错误的根本原因。

可行解决方案

1. 利用已获取的base64构建合法FormData

既然takePictureAsync已经开启了base64选项,直接用base64转Blob并组装请求是最可靠的方式:

import * as FileSystem from 'expo-file-system';

async function detectAnimal(base64Image) {
  const formData = new FormData();
  // 将base64转为Blob,指定正确的MIME类型
  const blob = await fetch(`data:image/jpeg;base64,${base64Image}`).then(res => res.blob());
  // 注意参数名必须符合iNaturalist要求:photo[image]
  formData.append('photo[image]', blob, { filename: 'animal_photo.jpg', type: 'image/jpeg' });
  formData.append('api_key', '你的API密钥');

  try {
    const response = await fetch('https://api.inaturalist.org/v1/observations/identify', {
      method: 'POST',
      // 不要手动设置Content-Type,浏览器会自动添加带boundary的正确头
      body: formData,
    });
    const result = await response.json();
    return result;
  } catch (err) {
    console.error('请求失败:', err);
  }
}

2. 避免直接传递本地URI的误区

Expo的本地URI是App沙箱内的私有路径,外部API无法访问,直接传递会触发422错误(服务器无法找到文件),必须将文件内容转为Blob或base64后再发送。

3. Axios请求的正确配置

如果用Axios,必须禁用自动设置Content-Type,让它自动识别multipart/form-data的边界:

import axios from 'axios';

async function detectAnimal(base64Image) {
  const blob = await fetch(`data:image/jpeg;base64,${base64Image}`).then(res => res.blob());
  const formData = new FormData();
  formData.append('photo[image]', blob, 'animal_photo.jpg');
  formData.append('api_key', '你的API密钥');

  try {
    const response = await axios.post(
      'https://api.inaturalist.org/v1/observations/identify',
      formData,
      { headers: {} } // 不要手动设置Content-Type
    );
    return response.data;
  } catch (err) {
    console.error('Axios请求错误:', err.response?.data || err.message);
  }
}

4. 图片压缩优化(可选)

如果图片过大导致请求失败,用Expo的ImageManipulator压缩:

import * as ImageManipulator from 'expo-image-manipulator';

async function compressBase64Image(base64Image) {
  const compressed = await ImageManipulator.manipulateAsync(
    `data:image/jpeg;base64,${base64Image}`,
    [{ resize: { width: 1200 } }], // 缩至1200px宽
    { format: ImageManipulator.SaveFormat.JPEG, quality: 0.75 }
  );
  return compressed.base64;
}

为什么Postman能成功?

Postman会自动处理multipart/form-data的边界和文件内容编码,你在Postman中选择本地文件时,它已经将文件转为符合要求的格式发送,而RN中错误的URI传递或Blob转换方式导致请求格式不匹配。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 08:32:38