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
相关产品推荐
相关产品推荐

