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

同一ReactApp下PC可连FastAPI服务器,移动端为何请求失败?

树莓派部署FastAPI+React后移动端Fetch请求失败问题

环境与现象

  • 主机:树莓派4B(系统:Raspbian GNU/Linux 10 (buster),因依赖兼容限制必须使用旧系统),部署FastAPI后端(8000端口)和React前端(3000端口)
  • 同一WiFi网络设备:Windows 11 PC客户端、Realme GT(Android 12)移动端客户端
  • 核心问题:
    • PC/移动端均能正常访问http://<树莓派IP>:3000显示React页面
    • PC端任意浏览器调用API完全正常
    • 移动端任意浏览器调用API均报failed to fetch错误

相关代码

React端Fetch请求代码

async function call_api(command) {
    try {
        const response = await fetch(`http://raspberrypi:8000/api/${command}`, {
            method: 'GET',
            headers: {
                accept: 'application/json',
            },
        })
        if (!response.ok) {
            console.error(`Error! status:  ${response.status}`);
        }

        const result_json = await response.json();
        console.log(result_json)
        return result_json;
    } catch (err) {
        console.error('Error:', err);
        alert(err) // 移动端可见提示
    }
}

FastAPI后端CORS配置

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

app = FastAPI()

origins = [
    "http://raspberrypi:3000", # 树莓派本地标识,用localhost无效
    "http://<PC_IP>:3000",
    "http://<移动端IP>:3000"
]

app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

@app.get("/api/{action}")
async def control(action: str):
    return {'action': action, 'success': True}

排查与解决方案

  • DNS解析问题:移动端大概率无法解析raspberrypi主机名(PC端因系统/路由器配置能正常解析),直接把Fetch请求中的http://raspberrypi:8000替换为树莓派的具体IP地址(如http://192.168.x.x:8000)
  • CORS配置遗漏:移动端访问的前端地址是http://<树莓派IP>:3000,该地址不在当前origins列表中,需将其添加进数组,或临时用"*"测试(生产环境不建议)
  • 树莓派端口限制:检查树莓派防火墙状态,执行sudo ufw status确认是否启用防火墙,若启用则添加规则sudo ufw allow 8000/tcp开放端口
  • 移动端网络干扰:确认移动端浏览器已获取网络权限,关闭代理、VPN等可能阻断请求的设置

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 23:23:32