388 lines
15 KiB
Markdown
388 lines
15 KiB
Markdown
# OTA固件API
|
||
|
||
<cite>
|
||
**本文引用的文件**
|
||
- [backend/src/routes/ota.js](file://backend/src/routes/ota.js)
|
||
- [backend/src/models/Ota.js](file://backend/src/models/Ota.js)
|
||
- [backend/src/services/otaStorage.js](file://backend/src/services/otaStorage.js)
|
||
- [backend/src/validators/ota.js](file://backend/src/validators/ota.js)
|
||
- [backend/src/utils/response.js](file://backend/src/utils/response.js)
|
||
- [backend/src/middleware/auth.js](file://backend/src/middleware/auth.js)
|
||
- [backend/src/config/env.js](file://backend/src/config/env.js)
|
||
- [frontend/src/api/ota.js](file://frontend/src/api/ota.js)
|
||
- [frontend/src/views/ota/index.vue](file://frontend/src/views/ota/index.vue)
|
||
- [backend/package.json](file://backend/package.json)
|
||
- [frontend/package.json](file://frontend/package.json)
|
||
</cite>
|
||
|
||
## 目录
|
||
1. [简介](#简介)
|
||
2. [项目结构](#项目结构)
|
||
3. [核心组件](#核心组件)
|
||
4. [架构总览](#架构总览)
|
||
5. [详细组件分析](#详细组件分析)
|
||
6. [依赖关系分析](#依赖关系分析)
|
||
7. [性能考量](#性能考量)
|
||
8. [故障排查指南](#故障排查指南)
|
||
9. [结论](#结论)
|
||
10. [附录](#附录)
|
||
|
||
## 简介
|
||
本文件为OTA固件管理API的完整RESTful接口文档,涵盖固件版本管理的HTTP方法、URL模式、请求/响应格式以及文件上传处理流程。内容包括:
|
||
- 固件版本列表查询、详情获取、创建、更新、删除接口
|
||
- 设备端“最新版本检查”接口
|
||
- 文件上传(Luxsin-X8上传至S3,Luxsin-X9保存到本地目录)
|
||
- 存储服务配置与使用示例
|
||
- 固件版本比较、强制更新策略与兼容性检查机制
|
||
- 下载链接生成、版本升级通知与错误处理实现指南
|
||
|
||
## 项目结构
|
||
后端采用Express + Sequelize + MySQL架构,前端基于Vue3 + Element Plus。OTA相关逻辑集中在路由、模型、服务层与验证器中,并通过统一响应封装返回。
|
||
|
||
```mermaid
|
||
graph TB
|
||
subgraph "前端"
|
||
FE_API["前端API模块<br/>frontend/src/api/ota.js"]
|
||
FE_VIEW["OTA页面视图<br/>frontend/src/views/ota/index.vue"]
|
||
end
|
||
subgraph "后端"
|
||
ROUTER["OTA路由<br/>backend/src/routes/ota.js"]
|
||
AUTH["认证中间件<br/>backend/src/middleware/auth.js"]
|
||
RESP["统一响应封装<br/>backend/src/utils/response.js"]
|
||
VALID["参数校验<br/>backend/src/validators/ota.js"]
|
||
MODEL["数据库模型<br/>backend/src/models/Ota.js"]
|
||
STORE["存储服务<br/>backend/src/services/otaStorage.js"]
|
||
ENV["环境配置<br/>backend/src/config/env.js"]
|
||
end
|
||
FE_API --> ROUTER
|
||
FE_VIEW --> FE_API
|
||
ROUTER --> AUTH
|
||
ROUTER --> VALID
|
||
ROUTER --> MODEL
|
||
ROUTER --> STORE
|
||
ROUTER --> RESP
|
||
STORE --> ENV
|
||
```
|
||
|
||
图表来源
|
||
- [backend/src/routes/ota.js:1-292](file://backend/src/routes/ota.js#L1-L292)
|
||
- [frontend/src/api/ota.js:1-68](file://frontend/src/api/ota.js#L1-L68)
|
||
- [frontend/src/views/ota/index.vue:1-628](file://frontend/src/views/ota/index.vue#L1-L628)
|
||
|
||
章节来源
|
||
- [backend/src/routes/ota.js:1-292](file://backend/src/routes/ota.js#L1-L292)
|
||
- [frontend/src/api/ota.js:1-68](file://frontend/src/api/ota.js#L1-L68)
|
||
- [frontend/src/views/ota/index.vue:1-628](file://frontend/src/views/ota/index.vue#L1-L628)
|
||
|
||
## 核心组件
|
||
- 路由层:定义所有OTA相关HTTP接口,包含设备端“最新版本检查”和后台管理接口。
|
||
- 认证中间件:保护后台接口,要求Bearer Token。
|
||
- 参数校验:使用Zod对创建/更新请求体进行严格校验。
|
||
- 数据模型:Sequelize定义的OTA表结构,包含版本号、MD5、强制更新、定向灰度、时间窗口等字段。
|
||
- 存储服务:根据设备型号选择不同存储路径(S3或本地),并生成公开下载链接。
|
||
- 响应封装:统一封装成功/错误/无数据三类响应格式。
|
||
|
||
章节来源
|
||
- [backend/src/middleware/auth.js:1-36](file://backend/src/middleware/auth.js#L1-L36)
|
||
- [backend/src/validators/ota.js:1-36](file://backend/src/validators/ota.js#L1-L36)
|
||
- [backend/src/models/Ota.js:1-97](file://backend/src/models/Ota.js#L1-L97)
|
||
- [backend/src/services/otaStorage.js:1-113](file://backend/src/services/otaStorage.js#L1-L113)
|
||
- [backend/src/utils/response.js:1-25](file://backend/src/utils/response.js#L1-L25)
|
||
|
||
## 架构总览
|
||
OTA接口分为两类:
|
||
- 设备端调用:无需登录,用于查询最新可升级版本。
|
||
- 后台管理:需登录,用于维护OTA版本列表、上传升级包、查看/编辑/删除。
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant Device as "设备端"
|
||
participant Router as "OTA路由"
|
||
participant Model as "数据库模型"
|
||
participant Logger as "日志"
|
||
Device->>Router : GET /api/ota/latest/check?currentVerCode&model&hw
|
||
Router->>Model : 查询 verCode > 当前版本且状态可用
|
||
alt 找到更高版本
|
||
Model-->>Router : 返回最高版本记录
|
||
Router-->>Device : 成功响应含下载URL、MD5、是否强制等
|
||
else 无更高版本
|
||
Router-->>Device : 无数据响应
|
||
end
|
||
Router->>Logger : 记录查询结果
|
||
```
|
||
|
||
图表来源
|
||
- [backend/src/routes/ota.js:68-102](file://backend/src/routes/ota.js#L68-L102)
|
||
- [backend/src/models/Ota.js:1-97](file://backend/src/models/Ota.js#L1-L97)
|
||
|
||
## 详细组件分析
|
||
|
||
### 设备端“最新版本检查”
|
||
- 方法与路径:GET /api/ota/latest/check
|
||
- 请求参数:
|
||
- currentVerCode: 当前设备版本号(整数)
|
||
- model: 设备型号(如 Luxsin-X8/X9)
|
||
- hw: 可选硬件版本号(整数)
|
||
- 响应:
|
||
- 成功:返回最高可用版本记录(含URL、MD5、是否强制更新、定向/灰度等)
|
||
- 无数据:表示无更高可用版本
|
||
- 兼容性与策略:
|
||
- 仅查询状态为可用且版本号大于当前版本的记录
|
||
- 支持按硬件版本过滤
|
||
- 强制更新字段用于客户端决定是否强制升级
|
||
|
||
章节来源
|
||
- [backend/src/routes/ota.js:68-102](file://backend/src/routes/ota.js#L68-L102)
|
||
|
||
### 后台管理接口(需登录)
|
||
|
||
#### 获取OTA版本列表
|
||
- 方法与路径:GET /api/ota/
|
||
- 查询参数:
|
||
- skip: 跳过条数(默认0)
|
||
- limit: 每页数量(默认100,最大1000)
|
||
- verCode: 精确匹配版本号
|
||
- verName: 模糊匹配版本名称
|
||
- model: 模糊匹配设备型号
|
||
- status: 状态(0/1)
|
||
- 响应:分页数据(items、total、skip、limit)
|
||
|
||
章节来源
|
||
- [backend/src/routes/ota.js:107-143](file://backend/src/routes/ota.js#L107-L143)
|
||
|
||
#### 获取指定OTA详情
|
||
- 方法与路径:GET /api/ota/:ota_id
|
||
- 路径参数:ota_id(整数)
|
||
- 响应:单条记录或无数据
|
||
|
||
章节来源
|
||
- [backend/src/routes/ota.js:145-160](file://backend/src/routes/ota.js#L145-L160)
|
||
|
||
#### 创建OTA版本
|
||
- 方法与路径:POST /api/ota/
|
||
- 请求体字段(必填/可选见校验规则):
|
||
- verCode: 整数(唯一性约束:同model下不可重复)
|
||
- verName: 字符串(1~20)
|
||
- url: 字符串(下载地址或上传后生成的URL)
|
||
- md5: 32位十六进制字符串
|
||
- force: 0/1(默认0)
|
||
- desc: 描述(可空)
|
||
- model: 设备型号(可空)
|
||
- hw: 硬件版本号(默认0)
|
||
- target: 是否定向(0/1,默认0)
|
||
- beta: 是否灰度(0/1,默认0)
|
||
- startTime/endTime: 时间字符串(可空)
|
||
- status: 状态(0/1,默认1)
|
||
- 响应:创建成功的记录
|
||
|
||
章节来源
|
||
- [backend/src/routes/ota.js:162-194](file://backend/src/routes/ota.js#L162-L194)
|
||
- [backend/src/validators/ota.js:1-36](file://backend/src/validators/ota.js#L1-L36)
|
||
- [backend/src/models/Ota.js:1-97](file://backend/src/models/Ota.js#L1-L97)
|
||
|
||
#### 更新OTA版本
|
||
- 方法与路径:PUT /api/ota/:ota_id
|
||
- 请求体字段:同创建接口(部分字段可为空表示不更新)
|
||
- 响应:更新后的记录
|
||
- 注意:
|
||
- 若更新版本号或设备型号,需保证新的组合在同model下唯一
|
||
- 日期字段会自动转换为Date类型
|
||
|
||
章节来源
|
||
- [backend/src/routes/ota.js:196-247](file://backend/src/routes/ota.js#L196-L247)
|
||
- [backend/src/validators/ota.js:19-33](file://backend/src/validators/ota.js#L19-L33)
|
||
|
||
#### 删除OTA版本
|
||
- 方法与路径:DELETE /api/ota/:ota_id
|
||
- 响应:删除成功消息
|
||
|
||
章节来源
|
||
- [backend/src/routes/ota.js:249-268](file://backend/src/routes/ota.js#L249-L268)
|
||
|
||
### 文件上传与存储
|
||
|
||
#### 接口:上传升级包
|
||
- 方法与路径:POST /api/ota/upload-package
|
||
- 请求头:Content-Type: multipart/form-data
|
||
- 表单字段:
|
||
- package_file: 二进制文件
|
||
- model: 设备型号(仅支持 Luxsin-X8 或 Luxsin-X9)
|
||
- 响应:
|
||
- 成功:返回md5、filename、url;X8同时返回s3_key
|
||
- 错误:返回错误信息(如未配置S3、上传失败、不支持的设备型号等)
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant Client as "客户端"
|
||
participant Router as "OTA路由"
|
||
participant Store as "存储服务"
|
||
participant S3 as "S3客户端"
|
||
participant FS as "本地文件系统"
|
||
Client->>Router : POST /api/ota/upload-package
|
||
Router->>Store : readUploadContentAndMd5(buffer)
|
||
alt model == Luxsin-X9
|
||
Store->>FS : 写入本地文件并生成URL
|
||
FS-->>Store : 返回保存名与URL
|
||
else model == Luxsin-X8
|
||
Store->>S3 : 上传对象并生成URL
|
||
S3-->>Store : 返回保存名、URL与S3 Key
|
||
end
|
||
Store-->>Router : {md5, filename, url[, s3_key]}
|
||
Router-->>Client : 成功响应
|
||
```
|
||
|
||
图表来源
|
||
- [backend/src/routes/ota.js:24-66](file://backend/src/routes/ota.js#L24-L66)
|
||
- [backend/src/services/otaStorage.js:46-103](file://backend/src/services/otaStorage.js#L46-L103)
|
||
|
||
#### 存储策略与配置
|
||
- 设备型号支持:Luxsin-X8、Luxsin-X9
|
||
- 存储方式:
|
||
- X8:上传至S3,生成公开访问URL
|
||
- X9:写入本地目录,生成公开访问URL
|
||
- 关键环境变量(来自存储服务):
|
||
- OTA_UPLOAD_DIR:本地上传根目录(开发默认临时目录,生产默认/data/projects/source)
|
||
- AWS_REGION/AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY:S3区域与凭证(无凭证时走IAM角色)
|
||
- AWS_S3_OTA_BUCKET:S3存储桶名称
|
||
- OTA_X8_PUBLIC_BASE:X8公开URL基础路径
|
||
- OTA_X9_URL_BASE:X9公开URL基础路径
|
||
|
||
章节来源
|
||
- [backend/src/services/otaStorage.js:12-25](file://backend/src/services/otaStorage.js#L12-L25)
|
||
- [backend/src/services/otaStorage.js:51-103](file://backend/src/services/otaStorage.js#L51-L103)
|
||
|
||
### 前端集成与使用示例
|
||
- 前端API模块提供:
|
||
- 列表、详情、创建、更新、删除、上传包等方法
|
||
- OTA页面视图:
|
||
- 支持搜索(版本名、设备型号、状态、版本号)
|
||
- 分页与表格展示
|
||
- 上传升级包(X8/X9)并回填URL与MD5
|
||
- 表单校验与提交
|
||
|
||
章节来源
|
||
- [frontend/src/api/ota.js:1-68](file://frontend/src/api/ota.js#L1-L68)
|
||
- [frontend/src/views/ota/index.vue:1-628](file://frontend/src/views/ota/index.vue#L1-L628)
|
||
|
||
## 依赖关系分析
|
||
|
||
```mermaid
|
||
classDiagram
|
||
class OtaRoute {
|
||
+GET "/api/ota/"
|
||
+GET "/api/ota/ : ota_id"
|
||
+POST "/api/ota/"
|
||
+PUT "/api/ota/ : ota_id"
|
||
+DELETE "/api/ota/ : ota_id"
|
||
+POST "/api/ota/upload-package"
|
||
+GET "/api/ota/latest/check"
|
||
}
|
||
class AuthMiddleware {
|
||
+authMiddleware()
|
||
}
|
||
class ApiResponse {
|
||
+success(data,msg)
|
||
+error(msg,code)
|
||
+noData(msg)
|
||
}
|
||
class OtaValidator {
|
||
+OtaCreateSchema
|
||
+OtaUpdateSchema
|
||
}
|
||
class OtaModel {
|
||
+verCode : int
|
||
+verName : string
|
||
+url : string
|
||
+md5 : string
|
||
+force : smallint
|
||
+desc : string
|
||
+model : string
|
||
+hw : int
|
||
+target : smallint
|
||
+beta : smallint
|
||
+startTime : date
|
||
+endTime : date
|
||
+status : smallint
|
||
}
|
||
class OtaStorage {
|
||
+readUploadContentAndMd5()
|
||
+saveX9PackageLocal()
|
||
+uploadX8PackageToS3()
|
||
}
|
||
OtaRoute --> AuthMiddleware : "保护后台接口"
|
||
OtaRoute --> OtaValidator : "参数校验"
|
||
OtaRoute --> OtaModel : "读写数据库"
|
||
OtaRoute --> OtaStorage : "文件上传"
|
||
OtaRoute --> ApiResponse : "统一响应"
|
||
```
|
||
|
||
图表来源
|
||
- [backend/src/routes/ota.js:1-292](file://backend/src/routes/ota.js#L1-L292)
|
||
- [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/validators/ota.js:1-36](file://backend/src/validators/ota.js#L1-L36)
|
||
- [backend/src/models/Ota.js:1-97](file://backend/src/models/Ota.js#L1-L97)
|
||
- [backend/src/services/otaStorage.js:1-113](file://backend/src/services/otaStorage.js#L1-L113)
|
||
|
||
## 性能考量
|
||
- 列表查询限制每页最大1000条,避免一次性返回过多数据。
|
||
- “最新版本检查”接口按verCode降序查询第一条,索引建议:
|
||
- 在verCode、model、status上建立复合索引以提升查询效率。
|
||
- 文件上传使用内存存储(multer.memoryStorage),大文件可能影响内存占用,建议:
|
||
- 控制上传文件大小与超时时间(前端已设置较长超时)。
|
||
- 对于X8大文件,优先考虑流式上传或分片上传策略(当前实现为一次性上传)。
|
||
|
||
[本节为通用性能建议,不直接分析具体文件]
|
||
|
||
## 故障排查指南
|
||
- 认证失败(401):
|
||
- 检查请求头Authorization是否为Bearer Token
|
||
- 确认Token未过期
|
||
- 参数校验失败:
|
||
- 按照Zod校验规则修正请求体字段(长度、类型、取值范围)
|
||
- 版本冲突:
|
||
- 创建/更新时若verCode与model组合重复,会返回“该版本已存在”
|
||
- S3上传失败:
|
||
- 检查AWS_REGION、AWS_ACCESS_KEY_ID、AWS_SECRET_ACCESS_KEY与AWS_S3_OTA_BUCKET配置
|
||
- 确认S3权限与存储桶存在
|
||
- 无可用版本:
|
||
- 设备端查询不到更高版本时返回“无数据”,确认目标设备型号、硬件版本与状态
|
||
|
||
章节来源
|
||
- [backend/src/middleware/auth.js:1-36](file://backend/src/middleware/auth.js#L1-L36)
|
||
- [backend/src/validators/ota.js:1-36](file://backend/src/validators/ota.js#L1-L36)
|
||
- [backend/src/routes/ota.js:174-181](file://backend/src/routes/ota.js#L174-L181)
|
||
- [backend/src/services/otaStorage.js:72-103](file://backend/src/services/otaStorage.js#L72-L103)
|
||
|
||
## 结论
|
||
本OTA固件API提供了完善的版本管理能力,支持设备端“最新版本检查”与后台管理功能,结合S3与本地存储策略满足不同设备型号的升级包分发需求。通过严格的参数校验与统一响应封装,提升了接口的稳定性与易用性。建议在生产环境中完善索引、优化大文件上传策略,并加强S3权限与监控告警。
|
||
|
||
[本节为总结性内容,不直接分析具体文件]
|
||
|
||
## 附录
|
||
|
||
### 统一响应格式
|
||
- 成功:code=1,msg为成功信息,data为返回数据
|
||
- 错误:code=0,msg为错误信息,data=null
|
||
- 无数据:code=2,msg为提示信息,data=null
|
||
|
||
章节来源
|
||
- [backend/src/utils/response.js:1-25](file://backend/src/utils/response.js#L1-L25)
|
||
|
||
### 设备端版本比较与强制更新策略
|
||
- 版本比较:仅返回verCode大于当前版本且状态为可用的最高版本
|
||
- 强制更新:由force字段控制,客户端据此决定是否强制升级
|
||
- 定向/灰度:target/beta字段可用于控制发布范围
|
||
|
||
章节来源
|
||
- [backend/src/routes/ota.js:77-89](file://backend/src/routes/ota.js#L77-L89)
|
||
- [backend/src/models/Ota.js:33-66](file://backend/src/models/Ota.js#L33-L66)
|
||
|
||
### 前端调用示例(参考)
|
||
- 列表查询:传入skip、limit、verName、model、status、verCode
|
||
- 上传包:构造FormData,包含package_file与model,设置Content-Type为multipart/form-data
|
||
- 提交表单:根据设备型号决定是否需要先上传包再填写URL/MD5
|
||
|
||
章节来源
|
||
- [frontend/src/api/ota.js:13-67](file://frontend/src/api/ota.js#L13-L67)
|
||
- [frontend/src/views/ota/index.vue:420-449](file://frontend/src/views/ota/index.vue#L420-L449) |