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

React Native Expo向FastAPI传图失败:Network request failed 求解

解决 React Native Expo 上传图片到 FastAPI 出现 Network request failed 的问题

问题场景

手机端运行 React Native Expo 应用,PC 端部署 FastAPI 后端服务,二者处于同一局域网,API 地址配置为 PC 的 IP 地址。尝试上传图片时,后端未接收到任何请求,前端抛出 TypeError: Network request failed 错误。

前端代码(React Native Expo)

import { router, useLocalSearchParams } from "expo-router";
import React, { useState } from "react";
import { View, Text, Image, TouchableOpacity, Alert, ActivityIndicator } from "react-native";

const API_URL = "http://<MY_IP_ADDRESS>:8000/analyze-image/";

const ImageScreen = () => {
  const { imageUri } = useLocalSearchParams<{ imageUri: string }>();
  const [isLoading, setIsLoading] = useState(false);

  const analyzeFood = async () => {
    setIsLoading(true);
    try {
      const formData = new FormData();

      const filename = imageUri.split('/').pop() || 'image.jpg';
      
      console.log(filename);
      console.log(imageUri);

      formData.append('image', {
        uri: imageUri,
        name: filename,
        type: 'image/jpeg',
      } as any);

      const response = await fetch(API_URL, {
        method: 'POST',
        body: formData,
        headers: {
          'Accept': 'application/json',
          'Content-Type': 'multipart/form-data',
        },
      });

      const data = await response.json();

      router.push({
        pathname: "/(meal)/analyzed-food",
        params: { 
          analysisData: JSON.stringify(data)
        },
      });
    } catch (error) {
      console.error('Error analyzing food:', error);
      Alert.alert(
        "Error",
        "Failed to analyze the food image. Please try again.",
        [{ text: "OK" }]
      );
    } finally {
      setIsLoading(false);
    }
  };

  return (
    <View className="flex-1 bg-white">
      <Image source={{ uri: imageUri }} className="w-full h-80" />
      <TouchableOpacity
        onPress={analyzeFood}
        disabled={isLoading}
        className={`bg-[#159339] py-3 my-8 mx-4 rounded-full items-center ${isLoading ? 'opacity-50' : ''}`}>
        {isLoading ? (
          <ActivityIndicator color="white" />
        ) : (
          <Text className="text-white text-lg font-bold">Analyze Food</Text>
        )}
      </TouchableOpacity>
    </View>
  );
};

export default ImageScreen;

后端代码(FastAPI)

from fastapi import FastAPI, UploadFile, File, HTTPException
from fastapi.middleware.cors import CORSMiddleware
import requests

app = FastAPI()

API_URL = "https://vision.foodvisor.io/api/1.0/en/analysis/"
API_KEY = <MY_API_KEY>

app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],  # Adjust this in production
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

@app.post("/analyze-image/")
async def analyze_image(image: UploadFile = File(...)):
    headers = {"Authorization": f"Api-Key {API_KEY}"}
    
    try:
        # Read the image file
        image_bytes = await image.read()
        files = {"image": (image.filename, image_bytes, image.content_type)}

        # Send the image to the API
        response = requests.post(API_URL, headers=headers, files=files)
        response.raise_for_status()  # Raise an error if the request failed

        # Parse the JSON response
        data = response.json()
        return {"data": data}

    except requests.HTTPError as e:
        raise HTTPException(status_code=response.status_code, detail=str(e))
    except Exception as e:
        raise HTTPException(status_code=500, detail="An error occurred while processing the image.")

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="127.0.0.1", port=8000)

解决方案

1. 修改 FastAPI 监听地址,允许局域网访问

当前后端用 127.0.0.1 启动,只能本地 PC 访问,手机无法连接。需要改成 0.0.0.0,让服务监听所有网卡:

# 替换后端启动代码
if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000)

2. 调整前端 FormData 请求配置

React Native 中手动设置 Content-Type: multipart/form-data 会丢失边界值(boundary),导致后端无法解析请求。同时要适配不同平台的 URI 格式:

// 先导入 Platform
import { Platform, View, Text, Image, TouchableOpacity, Alert, ActivityIndicator } from "react-native";

// 在 analyzeFood 函数中修改 FormData 和 fetch 部分
const analyzeFood = async () => {
  setIsLoading(true);
  try {
    const formData = new FormData();

    const filename = imageUri.split('/').pop() || 'image.jpg';
    // 适配 Android 平台的 URI 格式
    const uriForFormData = Platform.OS === 'android' ? imageUri : imageUri.replace('file://', '');

    formData.append('image', {
      uri: uriForFormData,
      name: filename,
      type: 'image/jpeg',
    } as any);

    const response = await fetch(API_URL, {
      method: 'POST',
      body: formData,
      headers: {
        'Accept': 'application/json',
        // 移除手动设置的 Content-Type,让系统自动生成带 boundary 的请求头
      },
    });

    // 后续代码不变...
  } catch (error) {
    // 错误处理不变...
  }
};

3. 验证网络连通性

  • 确认手机和 PC 连接同一 WiFi 网络
  • 在手机浏览器中访问 http://<PC_IP>:8000/docs,如果能打开 FastAPI 的文档页面,说明网络可达;如果打不开,检查 PC 防火墙是否拦截了 8000 端口,或者 IP 地址是否填写错误
  • 临时关闭 PC 端防火墙(测试用,生产环境需配置端口放行规则)

4. 确认图片 URI 有效性

前端已通过 Image 组件显示图片,说明 URI 有效,但可以额外打印 imageUri 的值,确认格式正确:

  • Android 通常是 content:// 开头
  • iOS 通常是 file:// 开头

内容的提问来源于stack exchange,提问作者Md. Sadmin Tahmid Khan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 19:04:56