概述
本文档说明如何将前端单页应用(SPA)接入到本 FastAPI 后端项目中。后端已经内置了 SPA 支持,可以无缝处理前端路由和静态资源。
目录结构约定
后端期望前端构建产物位于 src/static 目录:
project-tianlu/
├── src/
│ ├── app.py
│ ├── static/ # 前端构建产物目录(由前端构建生成)
│ │ ├── index.html
│ │ ├── assets/
│ │ └── ...
│ └── ...
└── ...
重要说明:
src/static/index.html:前端 SPA 的入口文件,必须存在其他静态资源(JS/CSS/图片等)也都在
src/static目录下
FastAPI 后端配置
后端在 src/app.py 中已经内置了 SPA 支持:
from fastapi.staticfiles import StaticFiles
from starlette.exceptions import HTTPException as StarletteHTTPException
class SPAStaticFiles(StaticFiles):
async def get_response(self, path: str, scope):
try:
return await super().get_response(path, scope)
except StarletteHTTPException as ex:
if ex.status_code == 404:
return await super().get_response("index.html", scope)
else:
raise ex
# 挂载 SPA 静态资源
app.mount("/", SPAStaticFiles(directory="src/static", html=True), name="app")
如果没有这段配置会有什么问题?
缺少
SPAStaticFiles的 404 回退逻辑时直接访问或刷新诸如
/report/list、/dashboard等前端路由时,请求会返回 后端的 404 JSON,而不是前端页面。因为默认
StaticFiles找不到对应的物理文件(例如/report/list),就直接抛出 404,不会再回退到index.html交给前端路由处理,SPA 的「前端路由 + 深链接」场景就会全部失效。
总结
SPAStaticFiles负责「把所有未知路径统一回退到index.html」,这是 SPA 正常支持浏览器刷新、深链接(直接访问任意前端路由)的关键。app.mount("/", ...)则负责「把前端静态资源挂到后端根路径」,否则后端根路径下根本没有前端页面可用。
工作原理:
所有非
/api开头的请求,都会优先按静态文件处理当找不到对应静态文件(404)时,统一返回
src/static/index.html,交由前端路由处理(典型 SPA 模式)
前端项目接入步骤
1. 配置前端构建输出目录为 src/static
Vue (Vite) 项目
在 vite.config.ts 中配置:
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
export default defineConfig({
plugins: [vue()],
build: {
outDir: '../src/static', // 输出到后端项目的 src/static 目录
},
// 如果后端挂载在根路径 `/`,base 保持默认即可
// base: '/',
})
React (Vite) 项目
在 vite.config.ts 中配置:
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
export default defineConfig({
plugins: [react()],
build: {
outDir: '../src/static', // 输出到后端项目的 src/static 目录
},
})
Vue CLI 项目
在 vue.config.js 中配置:
module.exports = {
outputDir: '../src/static', // 输出到后端项目的 src/static 目录
}
Create React App (CRA)
CRA 默认输出目录就是 build,需要修改为 src/static:
在 package.json 中修改构建脚本:
{
"scripts": {
"build": "react-scripts build && mv build ../src/static"
}
}
或者使用 react-app-rewired 自定义配置,设置 outputDir: '../src/static'。
2. 打包前端项目
在前端项目根目录执行:
# 安装依赖(如果还没有安装)
npm install
# 构建生产版本
npm run build
构建完成后,前端构建产物会直接输出到 src/static 目录。
3. 启动后端服务
在后端项目根目录执行:
# 使用 uv 运行
uv run uvicorn src.app:app --reload
# 或者使用其他方式
python -m uvicorn src.app:app --reload
打开浏览器访问:http://127.0.0.1:8000,应该能看到前端 SPA 页面。
4. API 调用说明
后端所有 API 路径统一挂载在 /api 前缀,例如:
GET /api/test_report/...POST /api/project/...GET /api/auth/...
前端调用时统一以 /api 开头发请求,确保与静态资源路由不冲突。
前端 API 调用示例:
// 使用 fetch
const response = await fetch('/api/test_report/list')
const data = await response.json()
// 使用 axios
import axios from 'axios'
const response = await axios.get('/api/test_report/list')
开发模式推荐
方式 A:前后端分离开发(推荐)
优点:前端热更新,开发效率高
前端开发服务器(前端项目目录):
npm run dev # 通常运行在 http://localhost:5173 (Vite)配置前端代理(Vite 示例):
在
vite.config.ts中配置:export default defineConfig({ server: { proxy: { '/api': { target: 'http://127.0.0.1:8000', changeOrigin: true, }, }, }, })后端开发服务器(后端项目目录):
uv run uvicorn src.app:app --reload访问方式:
前端页面:
http://localhost:5173API 请求会自动代理到
http://127.0.0.1:8000/api
方式 B:统一通过 FastAPI 访问
优点:更接近生产环境
每次修改前端后执行
npm run build构建产物会自动输出到
src/static目录启动后端服务,访问
http://127.0.0.1:8000
适用场景:前端改动不频繁,主要调试后端接口时使用
路由优先级说明
FastAPI 的路由匹配顺序很重要:
# 1. 先注册 API 路由(必须在静态文件之前)
app.include_router(src.auth.router.router, prefix="/api")
app.include_router(src.test_report.router.router, prefix="/api")
# ... 其他 API 路由
# 2. 最后挂载静态文件服务
app.mount("/", SPAStaticFiles(directory="src/static", html=True), name="app")
匹配规则:
以
/api开头的请求 → 匹配 API 路由 → 返回 JSON 响应其他请求 → 尝试静态文件 → 找不到则返回
index.html
生产环境部署建议
1. 使用 Nginx 反向代理(推荐)
生产环境建议使用 Nginx 处理静态文件,FastAPI 只处理 API 请求:
server {
listen 80;
server_name your-domain.com;
# 静态文件由 Nginx 直接提供
location / {
root /path/to/project/src/static;
try_files $uri $uri/ /index.html;
}
# API 请求转发到 FastAPI
location /api {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
2. 使用 Gunicorn + Uvicorn Workers
gunicorn src.app:app -w 4 -k uvicorn.workers.UvicornWorker --bind 0.0.0.0:8000
3. 使用 Docker 部署
可以创建一个包含前端构建产物和后端代码的 Docker 镜像,统一部署。
总结
✅ 前端构建产物放在
src/static目录✅ API 路由统一使用
/api前缀✅ API 路由必须在静态文件挂载之前注册
✅ 开发时推荐前后端分离,生产时统一部署
✅ 生产环境建议使用 Nginx 处理静态文件
按照以上步骤配置,即可将前端 SPA 无缝接入到 FastAPI 后端中。