如何在Docker中用FastAPI托管Vite.js React项目静态文件
FastAPI 托管 Vite React 静态文件统一部署方案
核心问题根因
你遇到的三类报错本质是三个通用配置坑:
- 静态文件路径使用了相对启动目录的硬编码路径,切换工作目录(从backend切到项目根目录、切到容器内工作目录)时路径解析失效
- 静态文件挂载方式不符合SPA单页应用的路由规则,且挂载顺序/前缀配置错误导致404
- Docker构建上下文配置错误,导致容器内前端静态文件没有被正确拷贝到对应路径
分步修复方案
1. 修复路径解析逻辑(彻底解决目录不存在报错)
不要用字符串形式的相对路径(比如frontend/dist、../frontend/dist),这类路径是相对于执行uvicorn命令时的工作目录解析的,和代码文件位置无关,切换启动位置就会失效。
基于当前Python代码文件的位置拼接绝对路径,和启动目录无关:
在你的backend/main.py中添加路径计算逻辑:
from pathlib import Path from fastapi import FastAPI from fastapi.staticfiles import StaticFiles from fastapi.responses import FileResponse app = FastAPI() # 计算绝对路径:BASE_DIR是当前main.py所在的backend目录的绝对路径 BASE_DIR = Path(__file__).resolve().parent # 前端构建产物目录:项目根目录/frontend/dist STATIC_ASSETS_DIR = BASE_DIR.parent / "frontend" / "dist"
2. 正确配置静态路由(解决访问404问题)
注意两个配置规则:
- 所有后端API路由要定义在静态路由之前,避免静态路由优先级过高覆盖API
- React是SPA应用,前端路由需要fallback到
index.html,原生StaticFiles挂载不支持自动fallback,需要单独加捕获路由
完整路由配置示例:
# 先定义所有后端API路由,举个例子 @app.get("/api/health") def health_check(): return {"status": "running"} # 挂载静态资源(js/css/fonts等带hash的资源,直接走StaticFiles即可) app.mount( "/assets", StaticFiles(directory=STATIC_ASSETS_DIR / "assets"), name="static-assets" ) # 捕获所有非API路径,处理SPA路由 @app.get("/{full_path:path}") def serve_frontend(full_path: str): # 如果请求路径对应dist目录下的真实文件(比如favicon.ico、根目录的logo等),直接返回文件 target_file = STATIC_ASSETS_DIR / full_path if target_file.is_file(): return FileResponse(target_file) # 其他所有路径(包括前端路由路径、不存在的前端路径)统一返回index.html,交给React Router处理 return FileResponse(STATIC_ASSETS_DIR / "index.html")
配置完成后本地验证:
- 在项目根目录执行
uvicorn backend.main:app可以正常启动,无目录不存在报错 - 在backend目录执行
uvicorn main:app同样可以正常启动 - 访问
http://127.0.0.1:8000即可正常打开前端页面,刷新前端子路由不会返回404 - 访问
/api/health等后端接口正常返回,不会被前端路由拦截
3. 修复Dockerfile配置(解决容器运行报错)
容器内报路径不存在,除了之前的硬编码相对路径问题,还有两个常见错误:Docker构建上下文选在backend目录导致无法拷贝frontend的文件、静态文件没有被正确拷贝到容器内的对应路径。
在项目根目录创建如下Dockerfile(不要放在backend目录):
# 第一阶段:构建前端产物 FROM node:20-alpine AS frontend-build WORKDIR /build/frontend COPY frontend/package*.json ./ RUN npm ci COPY frontend/ ./ RUN npm run build # 第二阶段:构建最终运行镜像 FROM python:3.11-slim WORKDIR /app # 安装后端依赖 COPY backend/requirements.txt ./ RUN pip install --no-cache-dir -r requirements.txt # 拷贝后端代码到/app/backend目录 COPY backend/ ./backend/ # 把前端构建的dist目录拷贝到/app/frontend/dist,和本地目录结构完全一致 COPY --from=frontend-build /build/frontend/dist ./frontend/dist/ EXPOSE 8000 # 启动服务,因为我们用了基于代码文件的绝对路径,这里工作目录不管怎么设都不会路径错误 CMD ["uvicorn", "backend.main:app", "--host", "0.0.0.0", "--port", "8000"]
构建镜像时必须在项目根目录执行构建命令,保证构建上下文能同时访问backend和frontend两个目录:
docker build -t fullstack-app .
运行容器后访问对应端口即可正常打开服务,不会出现目录不存在或404错误。
内容的提问来源于stack exchange,提问作者mrpbennett
相关产品推荐
相关产品推荐

