前后端分离_案例学习_Python+Flask+VUE3

学习笔记,仅供参考

主要学习笔记【Python Web】一文搞懂Flask框架:从入门到实战的完整指南-CSDN博客

目录

一、项目预览

1.1项目目录结构

1.2案例预览

1.3项目依赖

二、新手创建前后端项目

2.1前端VUE项目创建指令

[三、🏗️ 总体架构概述](#三、🏗️ 总体架构概述)

[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))

HTTP方法语义化

分页设计

[6. 中间件与拦截器](#6. 中间件与拦截器)

CORS中间件

JWT保护装饰器

[7. 错误处理机制](#7. 错误处理机制)

[3.2、🎨 前端架构详解 (Vue 3)](#3.2、🎨 前端架构详解 (Vue 3))

1.组件化架构

[2. 状态管理](#2. 状态管理)

[组件状态 vs 全局状态](#组件状态 vs 全局状态)

响应式系统原理

[3. 路由管理 (Vue Router)](#3. 路由管理 (Vue Router))

[4. HTTP客户端 (Axios)](#4. HTTP客户端 (Axios))

请求拦截器

API服务层封装

[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 把细节藏起来了

  1. 把数据变成"会叫的盒子"------ref

    const token = ref<string | null>(localStorage.getItem('access_token'))

  2. 谁在读?------计算属性

    const isAuthenticated = computed(() => !!token.value)

  3. 谁在写?------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"])
  1. 密码安全
python 复制代码
# 使用bcrypt哈希存储密码
password_hash = bcrypt.generate_password_hash(password).decode('utf-8')

3. JWT安全

  • Token设置过期时间

  • 使用HTTPS传输

  • 存储在HttpOnly Cookie中(最佳实践)

比喻理解:

想象你去健身房

  1. 登录(出示身份证)→ 前台验证身份

  2. 前台给你手环(JWT Token)

  3. 你拿着手环可以进入器械区、游泳池、更衣室

  4. 不需要每次都出示身份证

JWT是什么?

  • 令牌(Token):一个加密的字符串

  • 无状态:服务器不需要记住谁登录了

  • 自包含:Token里包含用户信息(如用户ID)

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwidXNlcm5hbWUiOiJhZG1pbiJ9.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

分为三部分(用.分隔):

  1. 🔒 Header(头):加密算法 {"alg": "HS256", "typ": "JWT"}

  2. 📋 Payload(载荷):数据 {"sub": "123", "username": "admin"}

  3. 🖋️ 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

可以直接从仓库拉取代码

相关推荐
HDO清风11 小时前
CASIA-HWDB2.x 数据集DGRL文件解析(python)
开发语言·人工智能·pytorch·python·目标检测·计算机视觉·restful
weixin_4997715511 小时前
Python上下文管理器(with语句)的原理与实践
jvm·数据库·python
weixin_4521595511 小时前
高级爬虫技巧:处理JavaScript渲染(Selenium)
jvm·数据库·python
多米Domi01111 小时前
0x3f 第48天 面向实习的八股背诵第五天 + 堆一题 背了JUC的题,java.util.Concurrency
开发语言·数据结构·python·算法·leetcode·面试
深蓝海拓11 小时前
PySide6从0开始学习的笔记(二十六) 重写Qt窗口对象的事件(QEvent)处理方法
笔记·python·qt·学习·pyqt
纠结哥_Shrek11 小时前
外贸选品工程师的工作流程和方法论
python·机器学习
小汤圆不甜不要钱11 小时前
「Datawhale」RAG技术全栈指南 Task 5
python·llm·rag
A懿轩A11 小时前
【Java 基础编程】Java 变量与八大基本数据类型详解:从声明到类型转换,零基础也能看懂
java·开发语言·python
Tansmjs12 小时前
使用Python自动收发邮件
jvm·数据库·python