# 数据流设计
**本文引用的文件**
- [backend/src/app.js](file://backend/src/app.js)
- [backend/src/config/env.js](file://backend/src/config/env.js)
- [backend/src/config/database.js](file://backend/src/config/database.js)
- [backend/src/config/redis.js](file://backend/src/config/redis.js)
- [backend/src/config/logger.js](file://backend/src/config/logger.js)
- [backend/src/middleware/auth.js](file://backend/src/middleware/auth.js)
- [backend/src/utils/response.js](file://backend/src/utils/response.js)
- [backend/src/utils/jwt.js](file://backend/src/utils/jwt.js)
- [backend/src/utils/password.js](file://backend/src/utils/password.js)
- [backend/src/routes/index.js](file://backend/src/routes/index.js)
- [backend/src/routes/brands.js](file://backend/src/routes/brands.js)
- [backend/src/models/Brand.js](file://backend/src/models/Brand.js)
- [backend/src/validators/brand.js](file://backend/src/validators/brand.js)
- [backend/src/services/measurementStorage.js](file://backend/src/services/measurementStorage.js)
- [backend/src/services/eqCacheStorage.js](file://backend/src/services/eqCacheStorage.js)
- [frontend/src/main.js](file://frontend/src/main.js)
- [frontend/src/utils/request.js](file://frontend/src/utils/request.js)
- [frontend/src/api/brand.js](file://frontend/src/api/brand.js)
## 目录
1. [引言](#引言)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构总览](#架构总览)
5. [详细组件分析](#详细组件分析)
6. [依赖关系分析](#依赖关系分析)
7. [性能考虑](#性能考虑)
8. [故障排查指南](#故障排查指南)
9. [结论](#结论)
10. [附录](#附录)
## 引言
本文件面向系统数据流与处理机制,覆盖从前端用户交互到后端数据持久化的完整路径;阐述 API 请求/响应模式、数据验证流程与错误传播机制;说明缓存策略、数据同步与一致性保障;并给出数据安全传输、加密存储与隐私保护建议,以及监控、性能分析与故障排查指引。
## 项目结构
系统采用前后端分离架构:
- 前端基于 Vue 3 + Element Plus,通过 Axios 封装的请求模块统一访问后端 /api 前缀接口。
- 后端基于 Express,使用中间件处理鉴权、请求体限制等;路由层组织各业务模块;模型层通过 Sequelize 访问 MySQL;服务层封装外部存储(S3)与缓存(Redis);统一响应格式与日志输出。
```mermaid
graph TB
FE["前端应用
Vue 3 + Element Plus"] --> AX["Axios 请求封装
/api 前缀"]
AX --> MW["Express 中间件
鉴权/请求体限制"]
MW --> RT["路由层
业务路由汇总"]
RT --> SVC["服务层
S3/Redis/业务逻辑"]
SVC --> DB["MySQL 数据库
Sequelize ORM"]
SVC --> S3["S3 对象存储"]
SVC --> RDS["Redis 缓存"]
```
图表来源
- [frontend/src/main.js:1-26](file://frontend/src/main.js#L1-L26)
- [frontend/src/utils/request.js:1-72](file://frontend/src/utils/request.js#L1-L72)
- [backend/src/app.js:1-60](file://backend/src/app.js#L1-L60)
- [backend/src/routes/index.js:1-13](file://backend/src/routes/index.js#L1-L13)
- [backend/src/config/database.js:1-24](file://backend/src/config/database.js#L1-L24)
- [backend/src/config/redis.js:1-32](file://backend/src/config/redis.js#L1-L32)
- [backend/src/services/measurementStorage.js:1-115](file://backend/src/services/measurementStorage.js#L1-L115)
- [backend/src/services/eqCacheStorage.js:1-73](file://backend/src/services/eqCacheStorage.js#L1-L73)
章节来源
- [frontend/src/main.js:1-26](file://frontend/src/main.js#L1-L26)
- [frontend/src/utils/request.js:1-72](file://frontend/src/utils/request.js#L1-L72)
- [backend/src/app.js:1-60](file://backend/src/app.js#L1-L60)
- [backend/src/routes/index.js:1-13](file://backend/src/routes/index.js#L1-L13)
## 核心组件
- 应用入口与中间件
- Express 应用初始化、CORS、JSON 解析、请求体大小限制、根路径与健康检查、路由注册、数据库同步与启动。
- 鉴权中间件
- Bearer Token 解析与校验,超时与无效凭证处理,超级管理员权限控制。
- 统一响应格式
- 成功/错误/无数据三态封装,分页数据容器。
- 数据库与缓存
- MySQL 连接配置与日志开关;Redis 连接池与错误日志。
- 外部存储服务
- S3 客户端按凭证或 IAM 角色自动选择;频响文件上传/下载与键构建规则。
- 前端请求封装
- 自动注入 Authorization 头、统一错误处理与 401/403 提示与跳转。
章节来源
- [backend/src/app.js:1-60](file://backend/src/app.js#L1-L60)
- [backend/src/middleware/auth.js:1-36](file://backend/src/middleware/auth.js#L1-L36)
- [backend/src/utils/response.js:1-25](file://backend/src/utils/response.js#L1-L25)
- [backend/src/config/database.js:1-24](file://backend/src/config/database.js#L1-L24)
- [backend/src/config/redis.js:1-32](file://backend/src/config/redis.js#L1-L32)
- [backend/src/services/measurementStorage.js:1-115](file://backend/src/services/measurementStorage.js#L1-L115)
- [frontend/src/utils/request.js:1-72](file://frontend/src/utils/request.js#L1-L72)
## 架构总览
下图展示典型“品牌管理”数据流:从前端发起请求,经鉴权中间件,到路由处理、模型查询与持久化,再到统一响应返回客户端。
```mermaid
sequenceDiagram
participant U as "用户界面"
participant F as "前端请求封装"
participant M as "鉴权中间件"
participant R as "品牌路由"
participant S as "品牌模型"
participant D as "MySQL 数据库"
U->>F : "GET /api/brands/"
F->>M : "携带 Bearer Token"
M-->>F : "校验通过/拒绝"
F->>R : "转发请求"
R->>S : "findAndCountAll()"
S->>D : "执行 SQL"
D-->>S : "结果集"
S-->>R : "rows/count"
R-->>F : "ApiResponse.success(...)"
F-->>U : "渲染列表"
```
图表来源
- [frontend/src/utils/request.js:1-72](file://frontend/src/utils/request.js#L1-L72)
- [backend/src/middleware/auth.js:1-36](file://backend/src/middleware/auth.js#L1-L36)
- [backend/src/routes/brands.js:1-147](file://backend/src/routes/brands.js#L1-L147)
- [backend/src/models/Brand.js:1-23](file://backend/src/models/Brand.js#L1-L23)
- [backend/src/utils/response.js:1-25](file://backend/src/utils/response.js#L1-L25)
## 详细组件分析
### 品牌管理数据流(含验证与错误传播)
- 前端调用
- 品牌 API 封装提供列表、详情、创建、更新、删除方法,均通过 /api 前缀访问。
- 路由与鉴权
- 所有品牌接口前置鉴权中间件;超级管理员权限可通过独立守卫控制。
- 业务处理
- 列表支持分页与模糊查询;创建/更新进行名称非空与唯一性校验;删除级联销毁。
- 错误传播
- 服务异常统一记录日志并返回统一错误响应;前端拦截 401/403 并引导至登录页或提示权限不足。
```mermaid
flowchart TD
Start(["进入路由处理"]) --> Validate["参数与输入校验"]
Validate --> Valid{"校验通过?"}
Valid -- 否 --> RespErr["返回统一错误响应"]
Valid -- 是 --> Oper["执行数据库操作"]
Oper --> DBOK{"数据库操作成功?"}
DBOK -- 否 --> LogErr["记录错误日志"] --> RespErr
DBOK -- 是 --> BuildResp["构建分页/对象响应"]
BuildResp --> Done(["返回统一成功响应"])
```
图表来源
- [backend/src/routes/brands.js:1-147](file://backend/src/routes/brands.js#L1-L147)
- [backend/src/utils/response.js:1-25](file://backend/src/utils/response.js#L1-L25)
- [backend/src/middleware/auth.js:1-36](file://backend/src/middleware/auth.js#L1-L36)
章节来源
- [frontend/src/api/brand.js:1-66](file://frontend/src/api/brand.js#L1-L66)
- [backend/src/routes/brands.js:1-147](file://backend/src/routes/brands.js#L1-L147)
- [backend/src/middleware/auth.js:1-36](file://backend/src/middleware/auth.js#L1-L36)
- [backend/src/utils/response.js:1-25](file://backend/src/utils/response.js#L1-L25)
### 验证与数据模型
- 输入验证
- 使用 Zod Schema 对创建/更新请求进行最小长度、最大长度与可选字段约束。
- 模型定义
- 品牌模型定义主键、唯一索引与注释,确保数据库层面约束一致。
- 业务约束
- 名称唯一性检查与更新时排除自身 ID 的冲突判断。
```mermaid
classDiagram
class BrandModel {
+id : number
+name : string
}
class BrandCreateSchema {
+name : string
}
class BrandUpdateSchema {
+name : string?
}
BrandModel <.. BrandCreateSchema : "约束输入"
BrandModel <.. BrandUpdateSchema : "约束输入"
```
图表来源
- [backend/src/models/Brand.js:1-23](file://backend/src/models/Brand.js#L1-L23)
- [backend/src/validators/brand.js:1-12](file://backend/src/validators/brand.js#L1-L12)
章节来源
- [backend/src/validators/brand.js:1-12](file://backend/src/validators/brand.js#L1-L12)
- [backend/src/models/Brand.js:1-23](file://backend/src/models/Brand.js#L1-L23)
### 缓存策略与一致性
- 缓存键设计
- EQ 缓存以“品牌+型号”作为 Redis Hash Key,字段为具体 EQ 参数键,避免一次性返回全部值导致响应过大。
- 读取策略
- 先 hkeys 获取字段列表,再按需 hget 读取具体字段值;未命中返回空字段列表。
- 一致性与容错
- 读取异常统一记录日志并抛出错误;缓存未命中不阻断主流程,可回退到数据库或外部存储。
```mermaid
flowchart TD
A["请求 EQ 字段列表"] --> B["构造 Redis Key"]
B --> C{"Key 是否存在?"}
C -- 否 --> D["返回空字段列表"]
C -- 是 --> E["hkeys 取字段名"]
E --> F["返回字段列表"]
G["请求 EQ 单字段值"] --> H["构造 Redis Key"]
H --> I["hget 读取"]
I --> J{"是否未命中?"}
J -- 是 --> K["抛出字段不存在错误"]
J -- 否 --> L["返回字段值"]
```
图表来源
- [backend/src/services/eqCacheStorage.js:1-73](file://backend/src/services/eqCacheStorage.js#L1-L73)
- [backend/src/config/redis.js:1-32](file://backend/src/config/redis.js#L1-L32)
章节来源
- [backend/src/services/eqCacheStorage.js:1-73](file://backend/src/services/eqCacheStorage.js#L1-L73)
- [backend/src/config/redis.js:1-32](file://backend/src/config/redis.js#L1-L32)
### 外部存储(S3)与数据同步
- S3 客户端
- 支持显式凭证或 IAM 角色访问;根据区域与桶名配置。
- 键构建规则
- 频响文件路径包含来源、佩戴方式、品牌首字母与品牌+型号文件名,便于检索与归档。
- 上传/下载
- 上传设置 Content-Type 为 CSV;下载读取字符串内容;对 404/NoSuchKey 映射为“未找到频响文件”。
```mermaid
sequenceDiagram
participant Svc as "测量存储服务"
participant S3 as "S3 客户端"
Svc->>Svc : "buildMeasurementKey()"
Svc->>S3 : "PutObjectCommand(Body=CSV)"
S3-->>Svc : "上传成功/失败"
Svc->>S3 : "GetObjectCommand(Key)"
S3-->>Svc : "返回内容/404"
```
图表来源
- [backend/src/services/measurementStorage.js:1-115](file://backend/src/services/measurementStorage.js#L1-L115)
章节来源
- [backend/src/services/measurementStorage.js:1-115](file://backend/src/services/measurementStorage.js#L1-L115)
### 前后端数据契约与错误传播
- 前端
- Axios 实例统一设置 baseURL=/api;请求头自动注入 Bearer Token(除登录接口);响应拦截器将 code=0 的业务错误标准化为异常并提示;401 清理本地认证并跳转登录。
- 后端
- 统一响应格式 ApiResponse.success/error/noData;路由层捕获异常并返回标准错误;日志记录关键信息。
```mermaid
sequenceDiagram
participant FE as "前端"
participant AX as "Axios 拦截器"
participant BE as "后端路由"
participant RESP as "统一响应"
FE->>AX : "发送请求"
AX->>BE : "注入 Authorization"
BE-->>RESP : "构造响应"
RESP-->>AX : "返回 {code,data,msg}"
AX-->>FE : "成功/错误处理"
```
图表来源
- [frontend/src/utils/request.js:1-72](file://frontend/src/utils/request.js#L1-L72)
- [backend/src/utils/response.js:1-25](file://backend/src/utils/response.js#L1-L25)
章节来源
- [frontend/src/utils/request.js:1-72](file://frontend/src/utils/request.js#L1-L72)
- [backend/src/utils/response.js:1-25](file://backend/src/utils/response.js#L1-L25)
## 依赖关系分析
- 组件耦合
- 路由依赖模型与服务;服务依赖数据库/缓存/S3;中间件贯穿所有受保护路由;前端仅依赖后端 /api 接口。
- 关键依赖链
- 品牌路由 → 品牌模型 → MySQL;品牌路由 → 统一响应;鉴权中间件 → JWT 工具;S3/Redis 服务 → 配置模块。
- 循环依赖
- 当前结构未见循环依赖迹象;路由汇总文件仅做导出聚合。
```mermaid
graph LR
R["品牌路由"] --> M["品牌模型"]
R --> U["统一响应"]
R --> S3["S3 存储服务"]
R --> RDS["Redis 缓存服务"]
MW["鉴权中间件"] --> JWT["JWT 工具"]
APP["应用入口"] --> MW
APP --> R
CFG["配置模块"] --> DB["数据库"]
CFG --> RDS
CFG --> LOG["日志"]
```
图表来源
- [backend/src/routes/brands.js:1-147](file://backend/src/routes/brands.js#L1-L147)
- [backend/src/models/Brand.js:1-23](file://backend/src/models/Brand.js#L1-L23)
- [backend/src/utils/response.js:1-25](file://backend/src/utils/response.js#L1-L25)
- [backend/src/services/measurementStorage.js:1-115](file://backend/src/services/measurementStorage.js#L1-L115)
- [backend/src/services/eqCacheStorage.js:1-73](file://backend/src/services/eqCacheStorage.js#L1-L73)
- [backend/src/middleware/auth.js:1-36](file://backend/src/middleware/auth.js#L1-L36)
- [backend/src/app.js:1-60](file://backend/src/app.js#L1-L60)
- [backend/src/config/database.js:1-24](file://backend/src/config/database.js#L1-L24)
- [backend/src/config/redis.js:1-32](file://backend/src/config/redis.js#L1-L32)
- [backend/src/config/logger.js](file://backend/src/config/logger.js)
章节来源
- [backend/src/routes/index.js:1-13](file://backend/src/routes/index.js#L1-L13)
- [backend/src/app.js:1-60](file://backend/src/app.js#L1-L60)
## 性能考虑
- 数据库
- 开发环境开启 SQL 日志便于调试;生产关闭日志以降低开销;分页 limit 最大值限制防止高负载。
- 缓存
- Redis 连接设置重试次数与连接超时;优先读取字段键列表,避免一次性返回大量字段值。
- 外部存储
- S3 上传设置明确 Content-Type;对 404/NoSuchKey 做快速错误映射,减少无效重试。
- 前端
- Axios 超时设置与错误提示,避免长时间挂起;401 自动跳转登录,减少无效请求。
章节来源
- [backend/src/config/database.js:1-24](file://backend/src/config/database.js#L1-L24)
- [backend/src/config/redis.js:1-32](file://backend/src/config/redis.js#L1-L32)
- [backend/src/services/measurementStorage.js:1-115](file://backend/src/services/measurementStorage.js#L1-L115)
- [frontend/src/utils/request.js:1-72](file://frontend/src/utils/request.js#L1-L72)
## 故障排查指南
- 401 未授权
- 前端检测到 401 清理本地认证并跳转登录页;后端鉴权中间件对缺失/过期/无效 Token 分类返回。
- 403 权限不足
- 超级管理员权限校验失败时返回相应提示。
- 业务错误
- 后端路由捕获异常并记录日志,返回统一错误响应;前端拦截 code=0 的业务错误并提示。
- 缓存问题
- Redis 读取失败记录错误日志;字段不存在抛出明确错误;可回退到数据库或外部存储。
- S3 问题
- 上传/下载失败记录错误日志;404 映射为“未找到频响文件”,便于前端提示。
章节来源
- [backend/src/middleware/auth.js:1-36](file://backend/src/middleware/auth.js#L1-L36)
- [frontend/src/utils/request.js:1-72](file://frontend/src/utils/request.js#L1-L72)
- [backend/src/utils/response.js:1-25](file://backend/src/utils/response.js#L1-L25)
- [backend/src/services/eqCacheStorage.js:1-73](file://backend/src/services/eqCacheStorage.js#L1-L73)
- [backend/src/services/measurementStorage.js:1-115](file://backend/src/services/measurementStorage.js#L1-L115)
## 结论
本系统通过统一的请求拦截、鉴权中间件、统一响应与日志体系,实现了从前端到后端的清晰数据流;结合 Redis 缓存与 S3 外部存储,兼顾了性能与扩展性;通过 Zod 校验与模型约束保障了数据质量。建议在生产中进一步完善指标埋点与告警、敏感字段加密存储与传输加密,持续优化缓存命中率与数据库查询计划。
## 附录
- 环境与部署
- 环境变量区分开发/生产;数据库与 Redis 默认值可按部署调整;日志模块集中输出。
- 安全与隐私
- 传输:建议启用 HTTPS;前端仅在受保护路由注入 Bearer Token;后端严格校验 Token。
- 存储:敏感字段建议加密存储;S3 访问凭证优先使用 IAM 角色;最小权限原则。
- 隐私:对用户标识与日志脱敏;仅保留必要审计日志。
章节来源
- [backend/src/config/env.js:1-13](file://backend/src/config/env.js#L1-L13)
- [backend/src/config/database.js:1-24](file://backend/src/config/database.js#L1-L24)
- [backend/src/config/redis.js:1-32](file://backend/src/config/redis.js#L1-L32)
- [backend/src/config/logger.js](file://backend/src/config/logger.js)