学习笔记,仅供参考
目录
[三、🏗️ 总体架构概述](#三、🏗️ 总体架构概述)
[3.1🔧 后端架构详解 (Flask)](#3.1🔧 后端架构详解 (Flask))
[1. 应用工厂模式](#1. 应用工厂模式)
[2. 蓝图 (Blueprints) - 模块化路由](#2. 蓝图 (Blueprints) - 模块化路由)
[3. 数据库层 (SQLAlchemy ORM)](#3. 数据库层 (SQLAlchemy ORM))
[4. 认证与授权 (JWT)](#4. 认证与授权 (JWT))
[5. API设计原则 (RESTful)](#5. API设计原则 (RESTful))
[6. 中间件与拦截器](#6. 中间件与拦截器)
[7. 错误处理机制](#7. 错误处理机制)
[3.2、🎨 前端架构详解 (Vue 3)](#3.2、🎨 前端架构详解 (Vue 3))
[2. 状态管理](#2. 状态管理)
[组件状态 vs 全局状态](#组件状态 vs 全局状态)
[3. 路由管理 (Vue Router)](#3. 路由管理 (Vue Router))
[4. HTTP客户端 (Axios)](#4. HTTP客户端 (Axios))
[5. 表单处理与验证](#5. 表单处理与验证)
[6. 数据绑定与事件通信](#6. 数据绑定与事件通信)
[3.3🔗 前后端通信模式](#3.3🔗 前后端通信模式)
[1. 请求-响应模式](#1. 请求-响应模式)
[2. 异步处理模式](#2. 异步处理模式)
[3. 数据序列化与反序列化](#3. 数据序列化与反序列化)
[3.4🛡️ 安全架构](#3.4🛡️ 安全架构)
[1. CORS安全策略](#1. CORS安全策略)
[3. JWT安全](#3. JWT安全)
[4. 输入验证](#4. 输入验证)
[3.5📊 性能优化架构](#3.5📊 性能优化架构)
[1. 数据库优化](#1. 数据库优化)
[2. 前端性能](#2. 前端性能)
[3. 缓存策略](#3. 缓存策略)
一、项目预览
1.1项目目录结构
后端
back/
├── blueprints/ # Flask蓝本模块
│ ├── init.py
│ ├── auth.py # 认证相关路由
│ └── todo.py # Todo相关路由
├── instance/ # 实例文件夹(存放配置文件等)
├── migrations/ # 数据库迁移文件夹
├── venv/ # Python虚拟环境
├── venv310 # Python 3.10虚拟环境
├── app.py # Flask应用主文件
├── extensions.py # Flask扩展初始化
├── init_db.py # 数据库初始化脚本
├── models.py # 数据库模型
├── requirements.txt # Python依赖包列表
├── schemas.py # 数据序列化模式
├── swagger.py # API文档配置
前端front/
├── public/ # 静态资源
├── src/
│ ├── router/ # Vue路由配置
│ │ └── index.ts # 路由主文件
│ ├── store/ # Vuex/Pinia状态管理
│ ├── views/ # 页面组件
│ │ ├── DebugPage.vue # 调试页面
│ │ ├── HomePage.vue # 首页
│ │ └── LoginPage.vue # 登录页面
│ ├── App.vue # 根组件
│ ├── main.ts # 应用入口文件
├── package.json # 项目依赖和脚本
├── tsconfig.json # TypeScript配置
├── vite-env.d.ts # Vite环境类型声明
├── vue.config.js # Vue CLI配置
└── yarn.lock # Yarn依赖锁定文件
1.2案例预览
LoginPage

HomePage

1.3项目依赖
requirements.txt
Flask==3.0.3 Flask-SQLAlchemy==3.0.5 Flask-Migrate==4.0.5 flask-smorest==0.46.2 marshmallow-sqlalchemy==0.3.0 Flask-JWT-Extended==4.5.3 Flask-Bcrypt==1.0.1 Flask-CORS==4.0.0 python-dotenv==1.0.0 SQLAlchemy==1.4.48
bash
# 用 3.10 建虚拟环境
&"C:\Users\木南朋友\AppData\Local\Programs\Python\Python310\python.exe" -m venv venv310
venv310\Scripts\activate
# 装兼容版本
pip install -r requirements.txt -i https://pypi.org/simple/
二、新手创建前后端项目
2.1前端VUE项目创建指令
bash
vue create vue3-demo
三、🏗️ 总体架构概述

3.1🔧 后端架构详解 (Flask)
1. 应用工厂模式
python
def create_app():
app = Flask(__name__)
# 配置、扩展初始化、蓝图注册
return app
2. 蓝图 (Blueprints) - 模块化路由
python
# 认证模块 在auth.py文件里面
auth_bp = Blueprint('auth', __name__)
# 任务模块 在todo.py文件里面
todo_bp = Blueprint('todo', __name__)
#蓝图导入 在app.py文件里面
from blueprints.auth import auth_bp
from blueprints.todo import todo_bp
# 注册蓝图
app.register_blueprint(auth_bp, url_prefix='/api/auth')
app.register_blueprint(todo_bp, url_prefix='/api/tasks')
3. 数据库层 (SQLAlchemy ORM)
ORM(对象关系映射)
比喻理解:
想象你只会说中文 ,要和一个只会说英文的人交流:
你(Python代
ORM(对象关系映射) 码)说:
user.username = "张三"翻译 (ORM)转换成英语:
UPDATE users SET username = '张三' WHERE id = 1对方(数据库)理解并执行
python
# ❌ 不用ORM(直接写SQL):
sql = "SELECT * FROM users WHERE username = 'admin'"
cursor.execute(sql)
# ✅ 用ORM(更简单安全):
user = User.query.filter_by(username='admin').first()
python
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True, nullable=False)
password_hash = db.Column(db.String(128), nullable=False)
class Todo(db.Model):
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, nullable=False)
title = db.Column(db.String(120), nullable=False)
done = db.Column(db.Boolean, default=False)
created_at = db.Column(db.DateTime, default=datetime.utcnow)
4. 认证与授权 (JWT)

Header: {"alg": "HS256", "typ": "JWT"}
Payload: {"sub": "用户ID", "exp": 过期时间, ...}
Signature: HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
5. API设计原则 (RESTful)
HTTP方法语义化

分页设计
GET /api/tasks?page=1&per_page=5
响应格式:
{
"items": [...],
"total": 20,
"page": 1,
"per_page": 5,
"pages": 4
}
python
# 分页查询 在todo.py文件中
pagination = Todo.query.filter_by(user_id=user_id).paginate(
page=page, per_page=per_page, error_out=False)
return jsonify({
'items': [task.to_dict() for task in pagination.items],
'total': pagination.total,
'page': pagination.page,
'per_page': pagination.per_page,
'pages': pagination.pages
})
jsonify把 Python 对象变成符合 HTTP 协议的 JSON 响应,同时自动设置正确的 Content-Type 和 UTF-8 编码。
6. 中间件与拦截器
CORS中间件
python
cors.init_app(app, resources={
r"/*": {
"origins": ["http://localhost:8082"],
"methods": ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
"allow_headers": ["Content-Type", "Authorization"],
"supports_credentials": True
}
})
JWT保护装饰器
python
@jwt_required()
它出现在每一个接口函数定义的正上方
当请求进入该接口时,
flask-jwt-extended会先检查 HTTP 头里的Authorization: Bearer <token>,验证通过后才继续执行函数体;否则直接返回 401/422,不会进入业务逻辑。把"JWT 保护装饰器"想成门禁卡
- 每个需要刷卡才能进的房间(接口)门口都装了一个读卡器------这个读卡器就是
@jwt_required()
进门时必须把门禁卡(登录后拿到的 token)放在读卡器上刷一下因此,只要看到函数头上贴着
@jwt_required()就说明:
"想调这个接口?先拿 token 来!"
7. 错误处理机制
统一错误响应格式
{
"error": "错误类型",
"message": "错误描述",
"code": 422
}
HTTP状态码语义
200: 成功
201: 创建成功
400: 请求错误(客户端)
401: 未授权
404: 资源不存在
422: 业务逻辑错误
500: 服务器内部错误
3.2、🎨 前端架构详解 (Vue 3)
1.组件化架构
<template>
<!-- HTML模板 -->
</template>
<script setup>
// JavaScript逻辑(Composition API)
</script>
<style scoped>
/* 组件作用域CSS */
</style>
2. 状态管理
组件状态 vs 全局状态
组件状态: 只在这一个 Vue 组件里有效,页面一关就消失,任何一个
.vue文件里用ref / reactive / useState定义的、只在该组件模板里用的变量。全局状态: 登录拿到的 token 应该放到 Pinia/Vuex 这类"全局仓库"里,整个项目随处都能用,
src/store/auth.ts里的useAuthStore()(Pinia 实例)
什么是"Pinia 实例"
Pinia 把"全局状态"封装成一个 可响应的、带方法的单例对象。
这个单例对象就是"Pinia 实例"。
谁在任何地方执行
const auth = useAuthStore()拿到的都是同一份 内存里的对象,所以它能跨组件、跨页面共享数据。
外部
const auth = useAuthStore() auth.setToken('xxx') // 写 console.log(auth.token) // 读
响应式系统原理
python
// Vue 3 Composition API
const count = ref(0) // 响应式引用
const doubleCount = computed(() => count.value * 2) // 计算属性
watch(count, (newVal) => console.log(newVal)) // 侦听器
Vue 的响应式系统 = 「用 Proxy 把数据包裹成 getter/setter」+「收集谁在用我」+「我变了就通知他们去更新」 。
这里用Pinia 把细节藏起来了
把数据变成"会叫的盒子"------
refconst token = ref<string | null>(localStorage.getItem('access_token'))
谁在读?------计算属性
const isAuthenticated = computed(() => !!token.value)
谁在写?------actions
function setToken(t: string) {
localStorage.setItem('access_token', t)
token.value = t // ← 触发 setter → trigger
}
3. 路由管理 (Vue Router)
python
// 路由配置
const routes = [
{ path: '/', redirect: '/login' },
{ path: '/login', component: LoginPage },
{
path: '/home',
component: HomePage,
meta: { requiresAuth: true } // 路由守卫
}
]
// 路由守卫(导航守卫)
router.beforeEach((to, from, next) => {
const hasToken = localStorage.getItem('token')
if (to.meta.requiresAuth && !hasToken) {
next('/login')
} else {
next()
}
})
4. HTTP客户端 (Axios)

请求拦截器
css
// 1. 创建实例
const api = axios.create({
baseURL: 'https://api.example.com',
timeout: 10000,
headers: { 'Content-Type': 'application/json' }
})
// 2. 请求拦截 → 发出去之前
api.interceptors.request.use(
config => {
const token = useAuthStore().token
if (token) config.headers.Authorization = `Bearer ${token}`
return config
},
error => Promise.reject(error)
)
// 3. 响应拦截 → 收到之后
api.interceptors.response.use(
response => {
// 统一 unwrap:接口总是返回 { code, data, msg }
const { code, data } = response.data
if (code === 0) return data // 业务成功
return Promise.reject(new Error(msg)) // 业务失败走 catch
},
error => {
// HTTP 状态码异常
const { response } = error
if (response?.status === 401) useAuthStore().logout()
ElMessage.error(response?.data?.msg || '网络错误')
return Promise.reject(error)
}
)
API服务层封装
把"裸 Axios 调用"变成按业务语义命名的函数
为什么多这一层
DTO = 前端"传过去"的数据结构;VO = 后端"返回来"的数据结构。
DTO ↔ VO 类型映射就是把这两端接口的 JSON 形状,用 TypeScript 接口描述出来 ,让 Axios 调用点直接享受到自动补全 + 类型检查。
css
/* ---------- 类型 ---------- */
export interface LoginDTO { username: string; password: string }
export interface LoginVO { access_token: string; expires_in: number }
/* ---------- 业务函数 ---------- */
export const authService = {
/** 登录 */
login(data: LoginDTO) {
return http.post<LoginVO>('/auth/login', data)
},
/** 刷新 Token */
refreshToken() {
return http.post<{ access_token: string }>('/auth/refresh').then(r => r.access_token)
},
/** 退出 */
logout() {
return http.post('/auth/logout')
}
}
组件用法(再也看不到 axios)
css
async function doLogin() {
try {
const res = await authService.login({ username: 'admin', password: '123' })
// res 已经是 LoginVO 类型
console.log(res.access_token)
} catch (e: any) {
ElMessage.error(e.message) // 拦截器已 unwrap
}
}
5. 表单处理与验证

6. 数据绑定与事件通信

事件通信(5 种)

原生 DOM 事件
html
<button @click="handleClick">save</button>
<input @keyup.enter="handleSearch"/>
组件自定义事件(子 → 父)
html
<!-- 子组件 -->
<script setup>
const emit = defineEmits(['update:modelValue', 'change'])
emit('change', val)
</script>
<!-- 父组件 -->
<Child @change="onChange" v-model="count"/>
全局事件总线(任意 ↔ 任意)
html
import mitt from 'mitt'
export const bus = mitt<{
login: { uid: number }
logout: void
}>()
// A 组件
bus.emit('login', { uid: 1 })
// B 组件
bus.on('login', payload => { ... })
provide / inject(祖 → 孙,无需 prop 层层钻)
html
<!-- 祖先 -->
const theme = ref('dark')
provide('theme', theme)
<!-- 孙组件 -->
const theme = inject<Ref<string>>('theme') // 响应式
状态管理(Pinia / Vuex)
html
import { useAuthStore } from '@/stores/auth'
const auth = useAuthStore()
auth.logout() // 任何组件同一实例
真正的全局响应式数据源 ;组件之间不直接通信 ,而是共同监听同一状态
3.3🔗 前后端通信模式
1. 请求-响应模式
python
// 前端发起请求
const response = await axios.get('/api/tasks')
// 后端处理并响应
@app.route('/api/tasks', methods=['GET'])
def get_tasks():
return jsonify({'tasks': tasks_list})
2. 异步处理模式
python
// 使用async/await处理异步
async function loadTasks() {
try {
const response = await taskAPI.getTasks()
tasks.value = response.data.items
} catch (error) {
console.error('加载失败:', error)
}
}
3. 数据序列化与反序列化
python
// 前端发送数据(自动JSON序列化)
axios.post('/api/tasks', {
title: '新任务',
done: false
})
// 后端接收并解析(自动JSON反序列化)
data = request.get_json()
3.4🛡️ 安全架构
1. CORS安全策略
是什么?
想象你在图书馆A 看书,但你想借图书馆B 的书。图书馆之间有个规则:A馆的读者不能直接进B馆的书架。
CORS就是这个规则:浏览器(图书馆管理员)会阻止一个网站的JavaScript(读者)访问另一个网站的数据(书)。
为什么需要?
-
默认禁止 :没有CORS时,
http://localhost:8082的网页不能 访问http://localhost:8083的API -
安全问题:防止恶意网站窃取你的数据
-
控制访问:只有被允许的网站才能访问你的API
python
# 后端告诉浏览器:"允许来自8082的访问"
cors.init_app(app, resources={
r"/*": {
"origins": ["http://localhost:8082"], # ✅ 允许的来源
"methods": ["GET", "POST", "PUT", "DELETE"], # ✅ 允许的方法
}
})
python
# 限制来源、方法、头信息
cors.init_app(app, origins=["http://localhost:8082"])
- 密码安全
python
# 使用bcrypt哈希存储密码
password_hash = bcrypt.generate_password_hash(password).decode('utf-8')
3. JWT安全
Token设置过期时间
使用HTTPS传输
存储在HttpOnly Cookie中(最佳实践)
比喻理解:
想象你去健身房:
-
你登录(出示身份证)→ 前台验证身份
-
前台给你手环(JWT Token)
-
你拿着手环可以进入器械区、游泳池、更衣室
-
不需要每次都出示身份证
JWT是什么?
令牌(Token):一个加密的字符串
无状态:服务器不需要记住谁登录了
自包含:Token里包含用户信息(如用户ID)
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwidXNlcm5hbWUiOiJhZG1pbiJ9.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
分为三部分(用.分隔):
🔒 Header(头):加密算法 {"alg": "HS256", "typ": "JWT"}
📋 Payload(载荷):数据 {"sub": "123", "username": "admin"}
🖋️ Signature(签名):验证签名
python
# 1. 登录时创建Token
def login():
user = User.query.filter_by(username='admin').first()
token = create_access_token(identity=str(user.id)) # 创建手环
return {'access_token': token}
# 2. 使用时验证Token
@jwt_required() # 检查手环
def get_tasks():
user_id = get_jwt_identity() # 从Token中获取用户ID
return tasks
4. 输入验证
python
# 后端验证
if not data or 'title' not in data:
return jsonify({'error': '需要任务标题'}), 400
3.5📊 性能优化架构
1. 数据库优化
python
# 使用分页避免大量数据查询
pagination = Todo.query.paginate(page=page, per_page=per_page)
# 添加索引
# 在模型中自动为主键添加索引,可为常用查询字段添加索引
2. 前端性能
组件懒加载
路由懒加载
图片懒加载
防抖和节流
3. 缓存策略
python
// 前端缓存
const cachedData = localStorage.getItem('cachedTasks')
if (cachedData) {
// 使用缓存
} else {
// 从服务器获取
}
四、项目代码
见文章绑定的资源 把所有项目代码都po出来了 大家可以自己下载本地运行一下
仅供参考!!!!!
更新 突然发现下载资源要会员
前后端分离_案例学习_Python_Flask_VUE3:前后端分离_案例学习_Python_Flask_VUE3 - AtomGit | GitCode
可以直接从仓库拉取代码


