FastAPI + Vue 前后端分离实战:我的项目结构“避坑指南”

先还原一个真实"案发现场"

小张花了一周写完FastAPI接口,用Postman测试全部通过,美滋滋地去睡了个好觉。第二天起床,信心满满地启动Vue项目,npm run dev,然后......控制台一片红Access-Control-Allow-Origin 错误。

赶紧上网搜,装了个flask-cors?不对,我是FastAPI。手忙脚乱加上CORSMiddleware,跨域是解决了,但POST请求又报422 Unprocessable Entity------前端传的JSON格式后端不认。

你可能会问:不就是配置个代理、写个接口吗?错!前后端分离的"分离"二字,坑全藏在细节里。下面我把最终稳定运行的结构和配置贴出来,你直接复制粘贴就能跑。

📁 我的"强迫症"项目结构(治好了我的精神内耗)

以前我喜欢把所有文件堆在一个文件夹里,后来发现维护起来像在垃圾堆里找钥匙。现在的结构长这样,按功能拆分明细,但又不至于过度拆分(别学我一开始拆了20个文件夹,结果自己都找不到东西)。

复制代码
fastapi_vue_project/
├── backend/                 # FastAPI后端
│   ├── app/
│   │   ├── api/            # 路由层(按模块分)
│   │   │   ├── v1/
│   │   │   │   ├── users.py
│   │   │   │   └── tasks.py
│   │   ├── core/           # 配置、安全、数据库连接
│   │   │   ├── config.py
│   │   │   └── database.py
│   │   ├── models/         # SQLAlchemy模型
│   │   ├── schemas/        # Pydantic模型(请求/响应结构)
│   │   ├── services/       # 业务逻辑层
│   │   └── main.py         # 入口
│   ├── requirements.txt
│   └── .env                # 环境变量(别提交到git!)
├── frontend/               # Vue3前端
│   ├── src/
│   │   ├── api/           # 封装axios请求
│   │   ├── views/         # 页面
│   │   ├── router/        # 路由
│   │   └── utils/         # 工具函数
│   └── .env.development   # 开发环境变量
│   └── .env.production    # 生产环境变量
└── docker-compose.yml      # 可选,线上部署用

👆 这个结构我用了很久,大小项目都稳得很。关键是 core/config.py 和 **frontend/.env.***这对"黄金搭档",解决了90%的环境切换问题。

🔌 通信的3个核心配置(少一个都连不上)

1️⃣ FastAPI的CORS中间件(不是加一行就完事的)

很多人复制官方示例allow_origins=["*"]就跑了,但生产环境千万别这么干 !而且你还要注意allow_credentialsallow_headers的配合。

复制代码
# backend/app/core/config.py
class Settings:
    BACKEND_CORS_ORIGINS = ["http://localhost:5173", "http://127.0.0.1:5173"]  # 开发环境
    # 生产环境从环境变量读取,不要写死

# backend/app/main.py
from fastapi.middleware.cors import CORSMiddleware

app.add_middleware(
    CORSMiddleware,
    allow_origins=settings.BACKEND_CORS_ORIGINS,  # 注意!不是 "*"
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["Authorization", "Content-Type"],
)

这里有个坑:如果你前端用axios 带上了withCredentials: true,后端allow_origins就不能是["*"],必须指定具体域名。当初我在这里卡了4个小时,最后翻FastAPI源码才找到原因。

2️⃣ Vue的代理配置(开发神器,但别滥用)

Vite(或webpack)的proxy 配置简直是开发阶段的救星,让你彻底告别跨域烦恼。但很多人抄完配置就不管了,结果部署到生产环境又报错。

复制代码
// frontend/vite.config.js
export default defineConfig({
  server: {
    proxy: {
      '/api': {
        target: 'http://localhost:8000',  // FastAPI默认端口
        changeOrigin: true,
        rewrite: (path) => path.replace(/^\/api/, '')  // 注意这个重写规则!
      }
    }
  }
})        

注意看rewrite这一行:如果你的FastAPI路由是@app.get("/users"),前端请求/api/users,代理会把/api去掉再转发。这里写错了路径,就会404。

3️⃣ 统一的响应格式(别让前端猜你返回什么)

这是我最想吐槽的一点:很多人后端返回的数据结构每天不一样,今天{"data": {...}},明天{"result": {...}}。前端大哥没被你气死算我输。

我的习惯:统一用下面的格式

复制代码
# backend/app/schemas/common.py
from pydantic import BaseModel
from typing import Generic, TypeVar, Optional

T = TypeVar('T')

class ResponseModel(BaseModel, Generic[T]):
    code: int = 200
    message: str = "success"
    data: Optional[T] = None

# 使用示例
@router.get("/users/{user_id}")
def get_user(user_id: int):
    user = service.get_user(user_id)
    return ResponseModel(data=user)

前端axios拦截器统一处理这个结构,代码量直接砍半 。是不是以为这样就完了?不,还有一个关于错误码的约定,建议至少约定401去登录、403无权限、422参数错误,别让前端去猜。

🌍 开发 vs 生产:别再手改baseURL了!

我见过最野的操作:每次部署前,手动把 axios 的 baseURL 从localhost:8000改成线上域名,然后commit,然后......忘了改回来。😱

正确姿势:用环境变量

复制代码
# frontend/.env.development
VITE_API_BASE_URL = '/api'   # 开发走代理

# frontend/.env.production
VITE_API_BASE_URL = 'https://your-api-domain.com'

// frontend/src/api/request.js
const request = axios.create({
    baseURL: import.meta.env.VITE_API_BASE_URL,
    timeout: 10000
})

后端也一样,用python-dotenv加载 .env 文件,永远不要把密钥写死在代码里

💣 再说三个容易翻车的点(都是真金白银换的教训)

⚠️ 第一个:路径拼接的斜杠

后端路由@app.get("/users"),前端请求/users/(多了一个斜杠),在nginx下可能301重定向,cookie丢了。

建议统一规则:路由末尾不加斜杠,前端请求也不加

⚠️ 第二个:请求/响应拦截器里的"循环引用"

有人在拦截器里用response.data.data取数据,但刷新token的接口又走了同一个拦截器,结果死循环。

解决方案:在白名单接口的meta里加一个标记跳过拦截器

⚠️ 第三个:FastAPI的异步陷阱

如果你用了async def,里面却调用同步的SQLAlchemy操作,会阻塞事件循环。

要么全用def,要么用asyncio.to_thread。很多人不知道,上了生产才发现接口越跑越慢。

🧠 进阶思考:拆分vs聚合,你的项目适合哪种?

相关推荐
IT_陈寒2 小时前
Python的asyncio把我整不会了,原来问题出在这儿
前端·人工智能·后端
Unity粉末状在校生2 小时前
清除microsoft edge账户信息
前端·microsoft·edge
walking9572 小时前
Vue3 日历组件选型指南:五大主流方案深度解析
前端·vue.js·面试
木心术12 小时前
设备管理网管系统:详细下一步行动指南
前端·人工智能·opencv
whuhewei2 小时前
Webpack5构建效率优化
前端·webpack
英俊潇洒美少年2 小时前
Vue、React.lazy、React 19 异步组件核心区别
javascript·vue.js·react.js
潍坊老登2 小时前
Flutter踩坑中
前端
大尚来也2 小时前
驾驭并发:.NET多线程编程的挑战与破局之道
java·前端·算法
快乐小土豆~~3 小时前
echarts柱状图的X轴label过长被重叠覆盖
前端·javascript·vue.js·echarts