完整功能实现
核心理念: 我们不是在学“写代码“,而是在学“用 AI 搭建系统“!
这一节会教你如何像设计师一样思考项目结构,然后让 AI 帮你填充代码细节。
📖 本节目标
学完本节,你将能够:
- ✅ 理解为什么要用三层架构(而不是死记硬背)
- ✅ 知道 JWT Token 和密码加密是什么、解决什么问题(AI 会帮你写具体代码)
- ✅ 学会用 AI 生成 Router/Service/DAO 的代码
- ✅ 看懂报错日志,知道该问 AI 什么问题
- ✅ 实现完整的用户注册+登录+验证流程(能跑起来就是成功!)
预计用时: 50 分钟(其中 40 分钟是让 AI 写代码,10 分钟是你理解架构)
💡 Vibe Coding 提醒
重要!开始前请记住:
- 这一节的代码很多都不需要你手写,看到复杂语法不要慌
- 我们会明确标注哪些部分“让 AI 写“,哪些部分“你需要理解“
- 如果遇到报错,先别急着放弃,报错信息就是给 AI 的“线索卡片“
1. 为什么要分层?(🎯 第一性原理:设计思维)
1.1 先别急着否定“简单代码“
之前你可能见过这样的代码(所有东西挤在一起):
@app.post("/api/users/register")
def register(data: UserRegisterRequest):
# 看起来很直观对吧?一眼就能看完整个流程
existing_user = supabase.table('users').select("*").eq('username', data.username).execute()
if existing_user.data:
return {"code": 400, "msg": "用户名已存在"}
password_hash = hashlib.sha256(data.password.encode()).hexdigest()
supabase.table('users').insert({
"username": data.username,
"password_hash": password_hash
}).execute()
return {"code": 200, "msg": "注册成功"}
✅ 对于初学者,这样写完全OK! 如果你只需要做一个简单的小网站(比如只有 3-5 个功能),这样写没问题。
1.2 但如果你想做“正经项目“,就需要“整理柜子“
现实问题:
- 就像把牙刷、衣服、锅碗瓢盆都塞进一个抽屉,刚开始还行,东西多了就乱套了
- 当你的网站有 20+ 个功能时,所有代码挤在一起会变成“意大利面条代码“,自己都找不到哪里出问题
三层架构 = 给柜子分格子:
用户请求 → Router(服务员) → Service(厨师) → DAO(仓库管理员) → 数据库
↓ ↓ ↓
返回响应 ← Router ← Service(做好菜) ← DAO(取到食材)
餐厅类比 (参考资料):
| 层次 | 职责 | 餐厅类比 | 真实工作 |
|---|---|---|---|
| Router | 接收请求、返回响应 | 服务员(点菜、上菜) | 接收用户的注册请求,返回“注册成功“ |
| Service | 业务逻辑处理 | 厨师(决定怎么做菜) | 检查用户名是否重复、密码加密 |
| DAO | 数据库操作 | 仓库管理员(取食材) | 从数据库查数据、往数据库存数据 |
关键理解:服务员不用懂厨师怎么炒菜,厨师不用懂仓库管理员怎么进货。他们各干各的,互不干扰。
1.3 为什么选三层而不是两层或四层?
设计思维:
- 两层不够:如果只有 Router 和数据库,那 Router 既要管接待客人,又要管做菜,又要管进货,太累了
- 四层太多:增加复杂度,小项目没必要
- 三层刚刚好:职责清晰,又不会过度设计
记住:这个架构不是“死规矩“,而是前人总结的“最佳实践“。你理解了原理,以后可以根据项目大小灵活调整。
2. 项目结构(🎯 第一性原理:框架理解)
2.1 先建立“脚手架“
下面是完整的项目结构。不要被吓到! 这些文件夹就像是搭积木前先摆好的空盒子。
my-backend/
├── main.py # 应用入口(房子的大门)
├── db_config.py # 数据库配置(水电开关)
├── routers/ # 路由层(接待处)
│ └── user_router.py
├── services/ # 服务层(工作室)
│ └── user_service.py
├── dao/ # 数据访问层(仓库)
│ └── user_dao.py
├── models/ # 数据模型(图纸)
│ └── user_model.py
├── utils/ # 工具类(工具箱)
│ ├── response.py # 统一响应(对讲机)
│ └── auth.py # JWT 认证(门禁卡)
└── requirements.txt # 依赖包(材料清单)
数据流向(框架理解核心):
1. 用户发请求 → main.py 收到
2. main.py 找到 user_router.py(服务员)
3. user_router 调用 user_service.py(厨师)
4. user_service 调用 user_dao.py(仓库)
5. user_dao 从 Supabase 数据库取数据
6. 数据原路返回 → 最终用户收到响应
2.2 🤖 让 AI 帮你创建文件结构
Vibe Coding 核心技巧:不要手动一个个建文件,用 AI!
复制这段话给 ChatGPT/Claude:
我要创建一个 FastAPI 后端项目,使用三层架构(Router/Service/DAO)。
请帮我生成创建以下文件夹结构的 shell 命令(适用于 Windows/Mac/Linux):
my-backend/
├── main.py
├── db_config.py
├── routers/
│ └── user_router.py
├── services/
│ └── user_service.py
├── dao/
│ └── user_dao.py
├── models/
│ └── user_model.py
├── utils/
│ ├── response.py
│ └── auth.py
└── requirements.txt
同时,请为每个 Python 文件生成一个最基本的空模板(只包含必要的 import 和注释),让我知道每个文件是干什么的。
AI 会返回:
- 创建文件夹的命令(如
mkdir -p routers services dao models utils) - 每个文件的空模板代码
- 你只需要复制粘贴运行即可!
2.3 理解术语(工具认知)
看到这些文件夹名可能会蒙,我们来用人话解释:
| 术语 | 人话解释 | 通俗比喻 |
|---|---|---|
| Router | 路由器 = 网址分配器 | 就像邮局,看地址(URL)把信送到对应部门 |
| Service | 服务 = 干活的部门 | 公司里的各个部门(人事部、财务部) |
| DAO | Data Access Object = 数据库搬运工 | 仓库管理员,只负责拿东西和放东西 |
| Model | 模型 = 数据的格式说明书 | 快递单上的格式(姓名、电话、地址) |
| utils | 工具 = 通用小工具 | 瑞士军刀,到处都能用 |
DAO 这个词特别迷惑:它的全称是 “Data Access Object”(数据访问对象),但你可以直接理解为**“数据库操作员”** —— 只有它有数据库的钥匙。
3. 核心概念速通(🎯 第一性原理:工具认知)
在看代码之前,先理解这些工具是干嘛的。记住:你只需要理解概念,具体语法让 AI 写!
3.1 JWT Token = 游乐园手环
问题:用户登录后,怎么证明“他还是他“?
传统方案(Session):
- 像银行给你一张存折,每次来都要查你的账户(服务器要记住每个人)
- 缺点:服务器累,用户多了就卡
现代方案(JWT Token) (详细解释):
- 就像游乐园的手环 (参考)
- 你买完票,工作人员给你手腕上戴个手环(这就是 Token)
- 之后你玩每个项目,只需要出示手环,工作人员验证后就让你通过
- 关键:手环上印着“有效期到今天晚上8点“,过期就得重新买票
JWT 的三部分(看不懂这些字母没关系,让 AI 写):
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxMjMsImV4cCI6MTcwMDAwMDAwMH0.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
───────────────────────────────── ────────────────────────────────────── ──────────────────────────────────────
Header(头部) Payload(内容) Signature(签名,防伪码)
说明加密算法 存用户ID、过期时间等 防止有人伪造手环
你需要理解的:
- ✅ JWT 是一串加密字符串,像身份凭证
- ✅ 登录成功后,服务器给用户发 Token
- ✅ 用户后续请求都要带上这个 Token(放在请求头 Header 里)
- ❌ 你不需要记住怎么写 JWT 的代码(让 AI 写!)
3.2 bcrypt 密码加密 = 把鸡蛋打碎做蛋饼
问题:用户密码怎么存?直接存 “123456” 会被黑客看光!
加密对比 (安全性解释):
| 方式 | 安全性 | 比喻 | 问题 |
|---|---|---|---|
| 明文 | ❌ 危险 | 密码写在纸上贴墙上 | 数据库泄露 = 所有密码泄露 |
| MD5/SHA256 | ⚠️ 一般 | 把密码打碎成粉末 | 相同密码打出来的粉末一样,可以用“彩虹表“破解 |
| bcrypt | ✅ 安全 | 每次打碎都加不同调料 | 同一密码每次加密结果都不同,黑客无法暴力破解 |
bcrypt 神奇的地方 (原理):
# 同一个密码 "123456",每次加密结果都不同!
hash1 = bcrypt.hash("123456")
# 结果:$2b$12$abc123...xyz789
hash2 = bcrypt.hash("123456")
# 结果:$2b$12$def456...uvw012 (完全不一样!)
# 但验证时都能认出来是 "123456"
bcrypt.verify("123456", hash1) # True
bcrypt.verify("123456", hash2) # True
就像做蛋饼:
- 你无法从蛋饼还原成生鸡蛋(单向不可逆)
- 每次做蛋饼加的调料不一样,看起来不同
- 但你尝一口就知道“这是用鸡蛋做的“(能验证)
你需要理解的:
- ✅ 密码必须加密存储,绝不能明文
- ✅ bcrypt 很安全,因为“每次结果都不同“
- ✅ bcrypt 故意设计得“慢一点“(0.1秒),让黑客破解时要花几百年
- ❌ 你不需要记 bcrypt 的 API(让 AI 写!)
3.3 🤖 AI 协作策略
接下来我们要写很多代码文件,但你不需要手写!
分工原则:
- 你负责:理解每个文件是干嘛的(Router/Service/DAO 的职责)
- AI 负责:写具体的代码语法
给 AI 的 Prompt 模板(复制修改使用):
我正在用 FastAPI + Supabase 开发后端,使用三层架构。
请帮我生成 [文件名] 的代码,需求如下:
1. [具体功能描述,比如"实现用户注册,检查用户名是否重复"]
2. 使用 bcrypt 加密密码
3. [其他特殊要求]
请包含完整的类型注解和中文注释。
示例:
我正在用 FastAPI + Supabase 开发后端,使用三层架构。
请帮我生成 services/user_service.py 的代码,需求如下:
1. 实现用户注册功能:检查用户名是否重复,使用 bcrypt 加密密码,调用 UserDAO 存储
2. 实现用户登录功能:验证密码,生成 JWT Token
3. 使用 python-jose 生成 JWT,密钥设为 "your-secret-key",有效期 7 天
请包含完整的类型注解和中文注释。
4. 完整代码实现(跟着 AI 一起搭建)
说明:下面的每个代码块会标注:
- 🤖 让 AI 写:复杂语法,直接复制或让 AI 生成
- 🧠 你需要理解:核心逻辑,必须看懂这部分在干嘛
- ⚙️ 改这里:你需要修改的配置(如数据库地址)
4.1 配置文件
db_config.py (数据库配置):
⚙️ 改这里 - 把 Supabase URL 和 Key 换成你的:
from supabase import create_client, Client
SUPABASE_URL = "https://xxx.supabase.co" # 替换
SUPABASE_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI..." # 替换
supabase: Client = create_client(SUPABASE_URL, SUPABASE_KEY)
4.2 统一响应格式
utils/response.py:
🧠 你需要理解:这个文件定义了“对讲机的统一格式“,所有接口返回的数据都用这个格式。
from typing import Optional, Any
from pydantic import BaseModel
class Response(BaseModel):
"""统一响应格式"""
code: int # 业务状态码
msg: str # 提示信息
data: Optional[Any] = None # 返回数据
class R:
"""响应工具类"""
@staticmethod
def success(data: Any = None, msg: str = "操作成功"):
return Response(code=200, msg=msg, data=data)
@staticmethod
def error(msg: str = "操作失败", code: int = 500):
return Response(code=code, msg=msg, data=None)
3.3 JWT 认证工具
安装依赖:
pip install python-jose[cryptography] passlib[bcrypt]
utils/auth.py:
from datetime import datetime, timedelta
from jose import JWTError, jwt
from passlib.context import CryptContext
from typing import Optional
# JWT 配置
SECRET_KEY = "your-secret-key-here" # 生产环境要用复杂的密钥
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_DAYS = 7
# 密码加密
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
def hash_password(password: str) -> str:
"""密码加密"""
return pwd_context.hash(password)
def verify_password(plain_password: str, hashed_password: str) -> bool:
"""验证密码"""
return pwd_context.verify(plain_password, hashed_password)
def create_access_token(data: dict, expires_delta: Optional[timedelta] = None):
"""生成 JWT Token"""
to_encode = data.copy()
if expires_delta:
expire = datetime.utcnow() + expires_delta
else:
expire = datetime.utcnow() + timedelta(days=ACCESS_TOKEN_EXPIRE_DAYS)
to_encode.update({"exp": expire})
encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
return encoded_jwt
def decode_access_token(token: str) -> Optional[dict]:
"""解析 JWT Token"""
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
return payload
except JWTError:
return None
3.4 数据模型
models/user_model.py:
from pydantic import BaseModel, Field, EmailStr
from typing import Optional
class UserRegisterRequest(BaseModel):
"""用户注册请求"""
username: str = Field(..., min_length=3, max_length=50)
password: str = Field(..., min_length=6)
email: Optional[EmailStr] = None
class UserLoginRequest(BaseModel):
"""用户登录请求"""
username: str = Field(..., min_length=3)
password: str = Field(..., min_length=6)
class UserResponse(BaseModel):
"""用户响应(不返回密码)"""
id: int
username: str
email: Optional[str]
created_at: str
3.5 DAO 层(数据访问层)
dao/user_dao.py:
from typing import Optional, Dict, Any
from db_config import supabase
class UserDAO:
"""
用户数据访问对象
职责:只负责数据库 CRUD 操作
"""
@staticmethod
def create(data: Dict[str, Any]) -> int:
"""创建用户"""
response = supabase.table('users').insert(data).execute()
return response.data[0]['id']
@staticmethod
def get_by_username(username: str) -> Optional[Dict[str, Any]]:
"""根据用户名查询用户"""
response = supabase.table('users').select("*").eq('username', username).execute()
return response.data[0] if response.data else None
@staticmethod
def get_by_id(user_id: int) -> Optional[Dict[str, Any]]:
"""根据 ID 查询用户"""
response = supabase.table('users').select("*").eq('id', user_id).execute()
return response.data[0] if response.data else None
@staticmethod
def list_all() -> list:
"""查询所有用户"""
response = supabase.table('users').select("id, username, email, created_at").execute()
return response.data
3.6 Service 层(服务层)
services/user_service.py:
from dao.user_dao import UserDAO
from utils.auth import hash_password, verify_password, create_access_token
class UserService:
"""
用户业务逻辑层
职责:业务逻辑处理、数据验证、密码加密等
"""
@staticmethod
def register(username: str, password: str, email: str = None) -> int:
"""
用户注册
Returns:
新创建的用户 ID
Raises:
Exception: 用户名已存在
"""
dao = UserDAO()
# 1. 检查用户名是否存在
if dao.get_by_username(username):
raise Exception("用户名已存在")
# 2. 密码加密
password_hash = hash_password(password)
# 3. 调用 DAO 创建用户
user_id = dao.create({
"username": username,
"password_hash": password_hash,
"email": email
})
return user_id
@staticmethod
def login(username: str, password: str) -> dict:
"""
用户登录
Returns:
包含 token 和用户信息的字典
Raises:
Exception: 用户名或密码错误
"""
dao = UserDAO()
# 1. 查询用户
user = dao.get_by_username(username)
if not user:
raise Exception("用户名或密码错误")
# 2. 验证密码
if not verify_password(password, user['password_hash']):
raise Exception("用户名或密码错误")
# 3. 生成 Token
token = create_access_token(data={"user_id": user['id'], "username": user['username']})
return {
"token": token,
"user": {
"id": user['id'],
"username": user['username'],
"email": user['email']
}
}
@staticmethod
def get_user_info(user_id: int) -> dict:
"""
获取用户信息
Raises:
Exception: 用户不存在
"""
dao = UserDAO()
user = dao.get_by_id(user_id)
if not user:
raise Exception("用户不存在")
return {
"id": user['id'],
"username": user['username'],
"email": user['email'],
"created_at": user['created_at']
}
3.7 Router 层(路由层)
routers/user_router.py:
from fastapi import APIRouter, Depends, HTTPException, Header
from models.user_model import UserRegisterRequest, UserLoginRequest
from services.user_service import UserService
from utils.response import R, Response
from utils.auth import decode_access_token
from typing import Optional
router = APIRouter(prefix="/api/users", tags=["用户管理"])
@router.post("/register", response_model=Response)
def register(data: UserRegisterRequest):
"""
用户注册接口
职责:
1. 接收请求参数
2. 调用服务层
3. 返回统一响应
"""
try:
user_id = UserService.register(
username=data.username,
password=data.password,
email=data.email
)
return R.success(msg="注册成功", data={"user_id": user_id})
except Exception as e:
return R.error(msg=str(e), code=400)
@router.post("/login", response_model=Response)
def login(data: UserLoginRequest):
"""用户登录接口"""
try:
result = UserService.login(
username=data.username,
password=data.password
)
return R.success(msg="登录成功", data=result)
except Exception as e:
return R.error(msg=str(e), code=400)
def get_current_user(authorization: Optional[str] = Header(None)):
"""
获取当前登录用户(依赖项)
用法:
@router.get("/profile")
def get_profile(user: dict = Depends(get_current_user)):
return R.success(data=user)
"""
if not authorization:
raise HTTPException(status_code=401, detail="未登录")
# 提取 Token(格式:Bearer xxx)
token = authorization.replace("Bearer ", "")
# 验证 Token
payload = decode_access_token(token)
if not payload:
raise HTTPException(status_code=401, detail="Token 无效或已过期")
return payload # 返回 {"user_id": 123, "username": "zhangsan"}
@router.get("/profile", response_model=Response)
def get_profile(current_user: dict = Depends(get_current_user)):
"""获取当前用户信息(需要登录)"""
try:
user_info = UserService.get_user_info(current_user['user_id'])
return R.success(data=user_info)
except Exception as e:
return R.error(msg=str(e), code=404)
@router.get("/list", response_model=Response)
def list_users():
"""查看所有用户(公开接口)"""
from dao.user_dao import UserDAO
users = UserDAO.list_all()
return R.success(data=users)
3.8 主程序入口
main.py:
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from routers import user_router
app = FastAPI(
title="我的后端 API",
description="使用三层架构的 FastAPI 项目",
version="1.0.0"
)
# CORS 跨域配置
app.add_middleware(
CORSMiddleware,
allow_origins=["*"], # 生产环境要改成具体域名
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# 注册路由
app.include_router(user_router.router)
@app.get("/")
def root():
return {"message": "Hello World", "docs": "/docs"}
if __name__ == "__main__":
import uvicorn
uvicorn.run("main:app", host="0.0.0.0", port=8000, reload=True)
3.9 依赖文件
requirements.txt:
fastapi
uvicorn[standard]
supabase
pydantic[email]
python-jose[cryptography]
passlib[bcrypt]
5. 报错不要慌!(🎯 第一性原理:问题定位)
重要心态调整:报错不是“失败“,而是系统在告诉你“哪里需要修复“。把报错信息当成AI 的线索卡片。
5.1 常见报错速查表
| 报错信息 | 人话翻译 | 责任归属 | 怎么办 |
|---|---|---|---|
ModuleNotFoundError: No module named 'xxx' | 缺少某个库 | 你的环境 | 运行 pip install xxx |
ImportError: cannot import name 'xxx' | 文件导入路径错了 | 你的代码 | 检查文件名和 import 语句 |
401 Unauthorized | Token 无效或过期 | 前端或用户 | 重新登录获取新 Token |
500 Internal Server Error | 服务器内部错误 | 后端代码 | 看终端日志,找具体错误行 |
connection refused | 数据库连不上 | 配置问题 | 检查 db_config.py 的 URL 和 Key |
5.2 怎么看报错日志?
示例报错:
Traceback (most recent call last):
File "/app/services/user_service.py", line 25, in register
user_id = dao.create({...})
File "/app/dao/user_dao.py", line 15, in create
response = supabase.table('users').insert(data).execute()
KeyError: 'id'
解读方法(从下往上看):
- 最后一行(
KeyError: 'id'):关键错误信息 = “找不到 ‘id’ 这个键” - 倒数第二行(
dao.py line 15):出错的具体位置 - 推理:Supabase 返回的数据里没有 ‘id’ 字段,可能是数据库表结构不对
🤖 把报错丢给 AI 的 Prompt:
我在运行 FastAPI + Supabase 项目时遇到以下报错:
[把完整报错信息粘贴在这里]
我的代码是这样的:
[粘贴出错的那几行代码]
请帮我分析原因并提供解决方案。
5.3 三层架构的报错定位
根据报错文件名判断是哪一层的问题:
报错文件 → 可能原因
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
user_router.py → 请求参数格式不对,或者调用 Service 的方式错了
user_service.py → 业务逻辑有问题(比如验证密码的逻辑错了)
user_dao.py → 数据库操作有问题(表名、字段名不对)
db_config.py → 数据库连接配置错误
auth.py → JWT 或密码加密的配置有问题
调试技巧:在怀疑的地方加 print() 或 logger.debug(),看看变量的值对不对。
5.4 验证 AI 代码的方法
问题:AI 写的代码怎么知道对不对?
验证清单:
- ✅ 能运行:
python main.py不报错,能访问/docs - ✅ 逻辑对:测试注册/登录流程,符合预期
- ✅ 错误处理:故意输入错误数据(如重复用户名),看能否正确返回错误信息
- ✅ 安全性:密码在数据库里是加密的(不是明文 “123456”)
如果 AI 代码有问题,这样问它:
你之前生成的 user_service.py 代码在测试时出现了 [具体问题描述]。
预期行为:[应该怎样]
实际行为:[实际怎样]
报错信息:[如果有]
请帮我修复这个问题。
6. 完整流程测试
6.1 启动应用
python main.py
访问 http://localhost:8000/docs
预期结果:看到 FastAPI 的自动文档界面,左侧列出了所有接口。
6.2 测试注册
POST /api/users/register
{
"username": "testuser",
"password": "123456",
"email": "test@example.com"
}
返回:
{
"code": 200,
"msg": "注册成功",
"data": {
"user_id": 1
}
}
6.3 测试登录
POST /api/users/login
{
"username": "testuser",
"password": "123456"
}
返回:
{
"code": 200,
"msg": "登录成功",
"data": {
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"user": {
"id": 1,
"username": "testuser",
"email": "test@example.com"
}
}
}
复制 token 备用!
6.4 测试获取用户信息(需要登录)
请求:
GET /api/users/profile
Headers:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
⚠️ 注意:Bearer 后面有个空格,别漏了!
在 /docs 中测试:
- 点击
GET /api/users/profile - 点击右上角 “Authorize” 锁头图标
- 在弹出框输入:
Bearer 你刚才复制的token(注意 Bearer 和 token 之间有空格) - 点击 “Authorize” 按钮
- 点击 “Try it out” → “Execute”
返回:
{
"code": 200,
"msg": "操作成功",
"data": {
"id": 1,
"username": "testuser",
"email": "test@example.com",
"created_at": "2025-01-15T10:30:00Z"
}
}
7. 理解三层架构(回顾与总结)
7.1 完整调用链路
用户注册的完整流程:
1. 用户请求
POST /api/users/register
{username: "zhangsan", password: "123456"}
2. Router 层(user_router.py)
├─ 接收请求参数
├─ 调用 UserService.register()
└─ 返回统一响应 R.success()
3. Service 层(user_service.py)
├─ 检查用户名是否存在(调用 DAO)
├─ 密码加密(hash_password)
├─ 调用 UserDAO.create()
└─ 返回用户 ID
4. DAO 层(user_dao.py)
├─ 执行数据库插入
└─ 返回新用户 ID
5. 数据库(Supabase)
└─ 存储用户数据
7.2 分层的好处
1. 单一职责:
- Router 只负责接收请求和返回响应
- Service 只负责业务逻辑
- DAO 只负责数据库操作
2. 易于测试:
# 可以单独测试服务层
def test_register():
user_id = UserService.register("testuser", "password123")
assert user_id > 0
3. 易于维护:
- 修改业务逻辑:只改 Service
- 修改数据库操作:只改 DAO
- 添加新接口:只加 Router
4. 代码复用:
# 多个接口可以复用同一个服务方法
@router.post("/api/users/register")
def register(data: UserRegisterRequest):
return UserService.register(...)
@router.post("/api/admin/users/create")
def admin_create_user(data: UserCreateRequest):
return UserService.register(...) # 复用
8. 常见问题(FAQ)
Q1: 为什么不用 Session 而用 JWT?
A:
| 特性 | Session | JWT |
|---|---|---|
| 存储位置 | 服务器 | 客户端 |
| 服务器压力 | 大 | 小(无状态) |
| 扩展性 | 差 | 好(适合分布式) |
| 适用场景 | 传统 Web | API 后端 |
Q2: SECRET_KEY 怎么生成?
A:
import secrets
# 生成安全的随机密钥
secret = secrets.token_hex(32)
print(secret)
# "a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6..."
Q3: Token 过期了怎么办?
A: 前端重新调用登录接口获取新 Token。
Q4: 怎么防止 Token 泄露?
A:
- ✅ 使用 HTTPS
- ✅ Token 设置过期时间
- ✅ 前端不要把 Token 打印到控制台
- ✅ 后端添加 IP 白名单(进阶)
💡 Vibe Coding 总结与反思
✅ 你已经掌握了什么?
恭喜!你现在已经能用 AI 搭建生产级别的后端了! 让我们回顾一下 Vibe Coding 的五大第一性原理:
1️⃣ 工具认知 ✅
- Router/Service/DAO:你知道每层是干嘛的(服务员/厨师/仓库管理员)
- JWT Token:游乐园手环,证明用户身份
- bcrypt:像做蛋饼,密码加密后无法还原
- Supabase:云端数据库,不用自己搭服务器
2️⃣ 问题定位 ✅
- 看懂报错日志:从下往上看,找最后一行的关键信息
- 三层架构定位:根据报错文件名(router/service/dao)判断哪一层的问题
- 常见报错速查表:知道 500/401/404 分别代表什么
- AI 调试助手:会把报错信息丢给 AI 求助
3️⃣ 框架理解 ✅
- 数据流向:用户请求 → Router → Service → DAO → 数据库 → 原路返回
- JWT 流程:登录 → 生成 Token → 客户端存储 → 后续请求带 Token → 服务器验证
- 密码安全:明文 → 加密 → 存储 → 登录验证
4️⃣ 设计思维 ✅
- 为什么分层:职责清晰、易于测试、易于维护、代码复用
- 为什么用 JWT 不用 Session:无状态、适合分布式、服务器压力小
- 为什么用 bcrypt 不用 MD5:每次加密结果不同、可以防彩虹表攻击
5️⃣ AI 协作 ✅
- 文件结构创建:让 AI 生成 shell 命令,不手动建文件
- 代码生成:给 AI 清晰的 Prompt,让它写具体代码
- 代码验证:知道怎么测试 AI 代码是否正确
- 报错修复:会把报错信息和代码一起发给 AI 求助
🎯 接下来你可以做什么?
实战任务(选一个尝试):
-
扩展功能:添加“修改密码“、“忘记密码“功能
- Prompt: “我想添加修改密码功能,需要验证旧密码后才能设置新密码,请帮我生成相应的 Service 和 Router 代码”
-
添加文章模块:实现发布文章、查看文章列表
- 先创建
article_dao.py,article_service.py,article_router.py - 让 AI 帮你生成 CRUD(增删改查)代码
- 先创建
-
前后端联调:把这个后端和前端项目连起来
- 前端用
fetch()或axios调用接口 - 记得处理 Token 存储和请求头
- 前端用
学习建议:
- ✅ 代码能跑就是成功,细节慢慢理解
- ✅ 多用 AI,把精力放在理解架构而非记语法
- ✅ 遇到报错别慌,报错是学习的最佳时机
- ✅ 实战出真知,做一个真实项目胜过看十篇教程
🤔 反思问题(巩固理解)
做完这个教程,问问自己:
- 工具认知:如果让你给别人解释“三层架构“,你能用餐厅比喻说清楚吗?
- 问题定位:遇到 500 错误,你知道第一步应该看哪里吗?
- 框架理解:你能画出用户注册时,数据从前端到数据库的完整流程图吗?
- 设计思维:为什么要用 JWT 而不是 Session?(用自己的话说)
- AI 协作:下次要添加新功能,你会怎么问 AI?
如果这 5 个问题你都能回答,说明你真的懂了 Vibe Coding 的精髓!
📚 深入学习资源
想进一步了解这些概念,推荐阅读:
🎉 最后的话
你不是在“学编程“,你是在“用 AI 解决问题“。
传统教育告诉你要“先学会语法再动手“,但 Vibe Coding 的理念是:
- 先理解问题(为什么需要用户登录?)
- 再理解方案(用 JWT Token 解决)
- 最后让 AI 写代码(具体语法交给机器)
记住:代码只是工具,思维才是核心。 你现在已经具备了用 AI 搭建后端系统的思维框架,恭喜你迈出了 Vibe Coding 的第一步!
去做点酷炫的东西吧! 🚀
📚 下一步
👉 技术术语手册
查阅常见技术术语的通俗解释,快速理解“黑话“。
返回 后端开发基础 查看完整目录。