410 lines
19 KiB
Markdown
410 lines
19 KiB
Markdown
# 开发指南
|
||
|
||
<cite>
|
||
**本文引用的文件**
|
||
- [README.md](file://README.md)
|
||
- [go.mod](file://go.mod)
|
||
- [Makefile](file://Makefile)
|
||
- [cmd/server/main.go](file://cmd/server/main.go)
|
||
- [internal/config/config.go](file://internal/config/config.go)
|
||
- [internal/router/router.go](file://internal/router/router.go)
|
||
- [internal/handler/health.go](file://internal/handler/health.go)
|
||
- [internal/handler/brand.go](file://internal/handler/brand.go)
|
||
- [internal/handler/model.go](file://internal/handler/model.go)
|
||
- [internal/middleware/logger.go](file://internal/middleware/logger.go)
|
||
- [internal/middleware/cors.go](file://internal/middleware/cors.go)
|
||
- [internal/middleware/request_id.go](file://internal/middleware/request_id.go)
|
||
- [internal/response/response.go](file://internal/response/response.go)
|
||
- [internal/repository/brand.go](file://internal/repository/brand.go)
|
||
- [internal/repository/model.go](file://internal/repository/model.go)
|
||
- [pkg/logger/logger.go](file://pkg/logger/logger.go)
|
||
</cite>
|
||
|
||
## 目录
|
||
1. [简介](#简介)
|
||
2. [项目结构](#项目结构)
|
||
3. [核心组件](#核心组件)
|
||
4. [架构总览](#架构总览)
|
||
5. [详细组件分析](#详细组件分析)
|
||
6. [依赖分析](#依赖分析)
|
||
7. [性能考虑](#性能考虑)
|
||
8. [故障排查指南](#故障排查指南)
|
||
9. [结论](#结论)
|
||
10. [附录](#附录)
|
||
|
||
## 简介
|
||
本开发指南面向新加入的开发者,帮助你快速理解并参与 Luxsin 应用 API 项目的开发。内容涵盖代码规范、测试策略、调试技巧、新增接口流程、代码审查要点、单元/集成/性能测试编写指南、调试工具与常见问题排查、扩展开发(插件机制与自定义中间件)、重构与性能优化、安全加固建议,以及开发环境配置与团队协作工作流。
|
||
|
||
## 项目结构
|
||
项目采用分层清晰的组织方式,围绕 Gin HTTP 框架构建,主要目录职责如下:
|
||
- cmd/server:应用入口,负责初始化配置、数据库、搜索引擎、缓存与路由,并启动 HTTP 服务。
|
||
- internal/config:集中加载与校验运行时配置(环境、主机、端口、数据库、搜索引擎、Redis)。
|
||
- internal/router:路由注册与中间件装配,按路径分组组织接口。
|
||
- internal/handler:HTTP 处理器,调用仓库层获取数据,使用统一响应体返回。
|
||
- internal/repository:数据访问层,封装 SQL 查询与扫描逻辑。
|
||
- internal/middleware:通用中间件(日志、CORS、请求 ID)。
|
||
- internal/response:统一 JSON 响应体结构与便捷函数。
|
||
- internal/search、internal/cache:外部服务客户端封装(搜索引擎、缓存)。
|
||
- pkg/logger:日志配置与初始化。
|
||
- sql:数据库初始化脚本。
|
||
- Makefile:常用命令(运行、构建、测试、依赖整理)。
|
||
- go.mod:模块与依赖声明。
|
||
|
||
```mermaid
|
||
graph TB
|
||
subgraph "入口与配置"
|
||
MAIN["cmd/server/main.go"]
|
||
CFG["internal/config/config.go"]
|
||
end
|
||
subgraph "网络层"
|
||
ROUTER["internal/router/router.go"]
|
||
MW_REQID["internal/middleware/request_id.go"]
|
||
MW_LOG["internal/middleware/logger.go"]
|
||
MW_CORS["internal/middleware/cors.go"]
|
||
end
|
||
subgraph "业务层"
|
||
HANDLER_HEALTH["internal/handler/health.go"]
|
||
HANDLER_BRAND["internal/handler/brand.go"]
|
||
HANDLER_MODEL["internal/handler/model.go"]
|
||
end
|
||
subgraph "数据访问层"
|
||
REPO_BRAND["internal/repository/brand.go"]
|
||
REPO_MODEL["internal/repository/model.go"]
|
||
end
|
||
subgraph "外部服务"
|
||
DB["MySQL"]
|
||
MS["Meilisearch"]
|
||
REDIS["Redis"]
|
||
end
|
||
MAIN --> CFG
|
||
MAIN --> ROUTER
|
||
ROUTER --> MW_REQID
|
||
ROUTER --> MW_LOG
|
||
ROUTER --> MW_CORS
|
||
ROUTER --> HANDLER_HEALTH
|
||
ROUTER --> HANDLER_BRAND
|
||
ROUTER --> HANDLER_MODEL
|
||
HANDLER_BRAND --> REPO_BRAND
|
||
HANDLER_MODEL --> REPO_MODEL
|
||
MAIN --> DB
|
||
MAIN --> MS
|
||
MAIN --> REDIS
|
||
```
|
||
|
||
图表来源
|
||
- [cmd/server/main.go:22-95](file://cmd/server/main.go#L22-L95)
|
||
- [internal/config/config.go:18-56](file://internal/config/config.go#L18-L56)
|
||
- [internal/router/router.go:14-41](file://internal/router/router.go#L14-L41)
|
||
- [internal/middleware/request_id.go:20-30](file://internal/middleware/request_id.go#L20-L30)
|
||
- [internal/middleware/logger.go:10-45](file://internal/middleware/logger.go#L10-L45)
|
||
- [internal/middleware/cors.go:7-20](file://internal/middleware/cors.go#L7-L20)
|
||
- [internal/handler/brand.go:19-49](file://internal/handler/brand.go#L19-L49)
|
||
- [internal/handler/model.go:19-50](file://internal/handler/model.go#L19-L50)
|
||
- [internal/repository/brand.go:20-50](file://internal/repository/brand.go#L20-L50)
|
||
- [internal/repository/model.go:20-61](file://internal/repository/model.go#L20-L61)
|
||
|
||
章节来源
|
||
- [README.md:5-17](file://README.md#L5-L17)
|
||
- [cmd/server/main.go:22-95](file://cmd/server/main.go#L22-L95)
|
||
- [internal/config/config.go:18-56](file://internal/config/config.go#L18-L56)
|
||
- [internal/router/router.go:14-41](file://internal/router/router.go#L14-L41)
|
||
|
||
## 核心组件
|
||
- 配置加载:集中读取环境变量并校验,支持开发/生产环境差异化。
|
||
- 路由与中间件:统一装配 Recovery、RequestID、Logger、CORS,按 /api/v1 与 /audio 分组注册接口。
|
||
- 处理器:品牌与型号查询,支持可选 Base64 响应编码。
|
||
- 仓库层:SQL 查询封装,上下文超时控制,错误包装。
|
||
- 统一响应:标准化 JSON 结构,内置 OK/Fail/BadRequest/InternalError 等便捷函数。
|
||
- 日志:开发/生产不同配置,输出请求级指标与错误信息。
|
||
- 外部服务:MySQL、Meilisearch、Redis 客户端初始化与使用。
|
||
|
||
章节来源
|
||
- [internal/config/config.go:18-56](file://internal/config/config.go#L18-L56)
|
||
- [internal/router/router.go:14-41](file://internal/router/router.go#L14-L41)
|
||
- [internal/handler/brand.go:26-49](file://internal/handler/brand.go#L26-L49)
|
||
- [internal/handler/model.go:26-50](file://internal/handler/model.go#L26-L50)
|
||
- [internal/repository/brand.go:20-50](file://internal/repository/brand.go#L20-L50)
|
||
- [internal/repository/model.go:20-61](file://internal/repository/model.go#L20-L61)
|
||
- [internal/response/response.go:15-36](file://internal/response/response.go#L15-L36)
|
||
- [pkg/logger/logger.go:8-19](file://pkg/logger/logger.go#L8-L19)
|
||
|
||
## 架构总览
|
||
下图展示从请求进入、中间件处理、路由分发到处理器与仓库层的完整链路,以及外部服务交互。
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant C as "客户端"
|
||
participant G as "Gin引擎"
|
||
participant M1 as "中间件 : RequestID"
|
||
participant M2 as "中间件 : Logger"
|
||
participant M3 as "中间件 : CORS"
|
||
participant R as "路由分组"
|
||
participant H as "处理器"
|
||
participant RP as "仓库层"
|
||
participant DB as "MySQL"
|
||
C->>G : "HTTP 请求"
|
||
G->>M1 : "注入/透传 RequestID"
|
||
M1->>M2 : "记录请求开始"
|
||
M2->>M3 : "设置跨域头"
|
||
M3->>R : "匹配路由"
|
||
R->>H : "分发到具体处理器"
|
||
H->>RP : "执行查询"
|
||
RP->>DB : "执行 SQL"
|
||
DB-->>RP : "结果集"
|
||
RP-->>H : "领域模型列表"
|
||
H-->>C : "统一响应体"
|
||
```
|
||
|
||
图表来源
|
||
- [cmd/server/main.go:64-64](file://cmd/server/main.go#L64-L64)
|
||
- [internal/router/router.go:16-19](file://internal/router/router.go#L16-L19)
|
||
- [internal/middleware/request_id.go:20-30](file://internal/middleware/request_id.go#L20-L30)
|
||
- [internal/middleware/logger.go:10-45](file://internal/middleware/logger.go#L10-L45)
|
||
- [internal/middleware/cors.go:7-20](file://internal/middleware/cors.go#L7-L20)
|
||
- [internal/handler/brand.go:26-49](file://internal/handler/brand.go#L26-L49)
|
||
- [internal/repository/brand.go:20-50](file://internal/repository/brand.go#L20-L50)
|
||
|
||
## 详细组件分析
|
||
|
||
### 组件:统一响应体
|
||
- 设计目标:所有接口返回一致的 JSON 结构,便于前端解析与错误处理。
|
||
- 关键点:OK 成功、Fail 自定义状态码与消息、BadRequest/InternalServerError 快捷函数。
|
||
- 使用建议:错误路径统一使用 Fail/内部错误函数,避免直接写原生 JSON。
|
||
|
||
```mermaid
|
||
classDiagram
|
||
class ResponseBody {
|
||
+int Code
|
||
+string Message
|
||
+any Data
|
||
}
|
||
class ResponseFuncs {
|
||
+OK(c, data)
|
||
+Fail(c, httpStatus, code, message)
|
||
+BadRequest(c, message)
|
||
+InternalError(c, message)
|
||
}
|
||
ResponseFuncs --> ResponseBody : "构造"
|
||
```
|
||
|
||
图表来源
|
||
- [internal/response/response.go:9-36](file://internal/response/response.go#L9-L36)
|
||
|
||
章节来源
|
||
- [internal/response/response.go:15-36](file://internal/response/response.go#L15-L36)
|
||
|
||
### 组件:中间件(日志、CORS、请求 ID)
|
||
- RequestID:生成或透传请求 ID,贯穿日志与追踪。
|
||
- Logger:记录状态码、方法、路径、延迟、IP、请求 ID、查询参数与错误。
|
||
- CORS:允许通配来源与常用方法/头,预检请求直接返回。
|
||
|
||
```mermaid
|
||
flowchart TD
|
||
Start(["进入中间件链"]) --> ReqID["注入/透传 RequestID"]
|
||
ReqID --> LogStart["记录请求开始信息"]
|
||
LogStart --> CORS["设置跨域头<br/>OPTIONS 预检短路"]
|
||
CORS --> Next["继续下一个处理器"]
|
||
Next --> LogEnd["计算耗时与状态码<br/>按级别输出日志"]
|
||
LogEnd --> End(["完成"])
|
||
```
|
||
|
||
图表来源
|
||
- [internal/middleware/request_id.go:20-30](file://internal/middleware/request_id.go#L20-L30)
|
||
- [internal/middleware/logger.go:10-45](file://internal/middleware/logger.go#L10-L45)
|
||
- [internal/middleware/cors.go:7-20](file://internal/middleware/cors.go#L7-L20)
|
||
|
||
章节来源
|
||
- [internal/middleware/request_id.go:10-30](file://internal/middleware/request_id.go#L10-L30)
|
||
- [internal/middleware/logger.go:10-45](file://internal/middleware/logger.go#L10-L45)
|
||
- [internal/middleware/cors.go:7-20](file://internal/middleware/cors.go#L7-L20)
|
||
|
||
### 组件:处理器(品牌、型号、健康检查)
|
||
- 健康检查:返回固定结构的“up”状态。
|
||
- 品牌列表:支持按名称模糊查询,可选 Base64 编码响应。
|
||
- 型号列表:支持按品牌或型号名过滤,可选 Base64 编码响应。
|
||
- 错误处理:捕获仓库层错误,记录日志并返回统一错误响应。
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant Client as "客户端"
|
||
participant Handler as "BrandHandler"
|
||
participant Repo as "BrandRepository"
|
||
participant DB as "MySQL"
|
||
Client->>Handler : "GET /audio/getBrand?brandName=..."
|
||
Handler->>Repo : "List(ctx, brandName)"
|
||
Repo->>DB : "QueryContext"
|
||
DB-->>Repo : "rows"
|
||
Repo-->>Handler : "[]Brand"
|
||
Handler-->>Client : "OK(data) 或 Base64(JSON)"
|
||
```
|
||
|
||
图表来源
|
||
- [internal/handler/brand.go:26-49](file://internal/handler/brand.go#L26-L49)
|
||
- [internal/repository/brand.go:20-50](file://internal/repository/brand.go#L20-L50)
|
||
|
||
章节来源
|
||
- [internal/handler/health.go:14-18](file://internal/handler/health.go#L14-L18)
|
||
- [internal/handler/brand.go:26-49](file://internal/handler/brand.go#L26-L49)
|
||
- [internal/handler/model.go:26-50](file://internal/handler/model.go#L26-L50)
|
||
|
||
### 组件:仓库层(SQL 查询封装)
|
||
- 上下文支持:所有查询使用 QueryContext,便于超时与取消。
|
||
- 条件拼接:根据输入动态拼接 WHERE 子句,避免无效查询。
|
||
- 扫描与空值:使用 NullString 包装可空字段,转换为指针类型。
|
||
- 错误包装:对查询、迭代、扫描阶段分别包装错误,便于定位。
|
||
|
||
```mermaid
|
||
flowchart TD
|
||
Enter(["进入 List(ctx, filters)"]) --> Build["拼接基础查询与参数"]
|
||
Build --> Exec["db.QueryContext(ctx, query, args...)"]
|
||
Exec --> Rows{"rows 是否为空?"}
|
||
Rows -- 是 --> ReturnEmpty["返回空列表"]
|
||
Rows -- 否 --> Iterate["遍历 rows 并 scanModel()"]
|
||
Iterate --> ScanOK{"scan 是否成功?"}
|
||
ScanOK -- 否 --> WrapErr["包装扫描错误并返回"]
|
||
ScanOK -- 是 --> Append["追加到结果切片"]
|
||
Append --> Done["返回结果"]
|
||
```
|
||
|
||
图表来源
|
||
- [internal/repository/brand.go:20-50](file://internal/repository/brand.go#L20-L50)
|
||
- [internal/repository/model.go:20-61](file://internal/repository/model.go#L20-L61)
|
||
- [internal/repository/model.go:63-86](file://internal/repository/model.go#L63-L86)
|
||
|
||
章节来源
|
||
- [internal/repository/brand.go:20-50](file://internal/repository/brand.go#L20-L50)
|
||
- [internal/repository/model.go:20-61](file://internal/repository/model.go#L20-L61)
|
||
- [internal/repository/model.go:63-95](file://internal/repository/model.go#L63-L95)
|
||
|
||
### 组件:配置加载与日志
|
||
- 配置加载:读取环境变量,自动选择数据库配置,校验各组件配置。
|
||
- 日志:开发使用彩色开发配置,生产使用生产配置并调整时间键与编码。
|
||
|
||
```mermaid
|
||
flowchart TD
|
||
Start(["Load()"]) --> Env["读取 APP_ENV/PORT/HOST"]
|
||
Env --> DB["loadDatabase(env) validate()"]
|
||
DB --> MS["loadMeilisearch validate()"]
|
||
MS --> RD["loadRedis validate()"]
|
||
RD --> Build["组装 Config 并返回"]
|
||
```
|
||
|
||
图表来源
|
||
- [internal/config/config.go:18-56](file://internal/config/config.go#L18-L56)
|
||
- [pkg/logger/logger.go:8-19](file://pkg/logger/logger.go#L8-L19)
|
||
|
||
章节来源
|
||
- [internal/config/config.go:18-56](file://internal/config/config.go#L18-L56)
|
||
- [pkg/logger/logger.go:8-19](file://pkg/logger/logger.go#L8-L19)
|
||
|
||
## 依赖分析
|
||
- 模块与依赖:使用 Gin、MySQL 驱动、Meilisearch SDK、Redis 客户端、Zap 日志。
|
||
- 间接依赖:大量第三方库用于 JSON、加密、并发、压缩等。
|
||
- 版本管理:通过 go.mod 管理,使用 Makefile 的 tidy 命令维护依赖一致性。
|
||
|
||
```mermaid
|
||
graph LR
|
||
MOD["go.mod"] --> GIN["github.com/gin-gonic/gin"]
|
||
MOD --> MYSQL["github.com/go-sql-driver/mysql"]
|
||
MOD --> MEILI["github.com/meilisearch/meilisearch-go"]
|
||
MOD --> REDIS["github.com/redis/go-redis/v9"]
|
||
MOD --> ZAP["go.uber.org/zap"]
|
||
```
|
||
|
||
图表来源
|
||
- [go.mod:5-11](file://go.mod#L5-L11)
|
||
|
||
章节来源
|
||
- [go.mod:1-47](file://go.mod#L1-L47)
|
||
- [Makefile:12-13](file://Makefile#L12-L13)
|
||
|
||
## 性能考虑
|
||
- 超时控制:仓库层使用 QueryContext,建议在入口处设置合理超时,避免慢查询拖垮服务。
|
||
- 日志开销:生产环境日志级别更高,避免在高频路径中进行昂贵的日志格式化。
|
||
- 响应体积:当数据量较大时,可启用 Base64 响应以减少传输体积,但需权衡 CPU 开销。
|
||
- 连接池:确保数据库、Redis、搜索引擎连接池参数合理,避免连接争用。
|
||
- 中间件顺序:将轻量中间件前置,重逻辑后置,减少对正常路径的影响。
|
||
- 缓存策略:对热点查询结果进行缓存,降低数据库压力。
|
||
|
||
## 故障排查指南
|
||
- 健康检查失败:确认 /api/v1/health 能返回状态 up;若失败,查看日志中 server startup/shutdown 相关条目。
|
||
- 数据库连接失败:核对 DATABASE_* 环境变量与网络连通性;生产环境密码必须通过环境变量注入。
|
||
- 跨域问题:确认中间件已装配且 OPTIONS 预检返回 204;检查前端请求头是否包含允许的字段。
|
||
- 请求无日志:确认 Logger 中间件已正确装配,且 RequestID 已透传。
|
||
- 响应异常:检查处理器是否使用统一响应函数;错误路径是否调用了 InternalError/BadRequest。
|
||
- 接口无响应:检查路由分组与路径是否正确;确认处理器实例已创建并注册。
|
||
|
||
章节来源
|
||
- [README.md:83-99](file://README.md#L83-L99)
|
||
- [internal/router/router.go:27-38](file://internal/router/router.go#L27-L38)
|
||
- [internal/middleware/logger.go:10-45](file://internal/middleware/logger.go#L10-L45)
|
||
- [internal/middleware/cors.go:7-20](file://internal/middleware/cors.go#L7-L20)
|
||
- [internal/response/response.go:15-36](file://internal/response/response.go#L15-L36)
|
||
|
||
## 结论
|
||
本指南提供了从项目结构、核心组件到扩展开发与运维排错的完整指引。建议在新增接口时严格遵循“处理器-仓库-统一响应”的分层设计,配合中间件与配置体系,确保可维护性与可观测性。后续可在此基础上引入鉴权、限流、熔断与可观测性组件,逐步完善系统能力。
|
||
|
||
## 附录
|
||
|
||
### 新增接口标准流程
|
||
- 在 internal/handler 下新建处理器文件,定义 NewXxxHandler 与 XxxHandler 方法。
|
||
- 在 internal/router/router.go 的相应分组下注册路由与处理器。
|
||
- 在 internal/repository 中补充必要的查询方法,使用 QueryContext 并包装错误。
|
||
- 使用 internal/response 统一返回响应。
|
||
- 编写单元测试与集成测试,覆盖正常与异常路径。
|
||
- 如需跨域或特殊头部,更新中间件或在处理器内设置。
|
||
|
||
章节来源
|
||
- [README.md:111-116](file://README.md#L111-L116)
|
||
- [internal/router/router.go:27-38](file://internal/router/router.go#L27-L38)
|
||
|
||
### 代码规范与审查要点
|
||
- 命名规范:包名小写、结构体与方法首字母大写、常量与全局变量见名知意。
|
||
- 错误处理:所有错误必须被记录或向上返回;避免忽略错误。
|
||
- 日志:区分 Info/Warn/Error 级别;记录关键上下文(如请求 ID、状态码、耗时)。
|
||
- 配置:敏感信息通过环境变量注入;生产环境禁止硬编码。
|
||
- 中间件:保持单一职责;避免在中间件中做重逻辑。
|
||
- 测试:每个处理器至少包含正常与错误场景;仓库层覆盖条件分支。
|
||
|
||
### 测试策略与编写指南
|
||
- 单元测试:针对处理器与仓库层,使用内存数据库或模拟对象隔离外部依赖。
|
||
- 集成测试:启动最小化服务,验证路由、中间件、配置与外部服务连通性。
|
||
- 性能测试:使用压测工具对关键接口施压,观察 P95/P99 延迟与错误率,结合日志定位瓶颈。
|
||
- 建议工具:go test、vegeta、hey、pprof。
|
||
|
||
章节来源
|
||
- [Makefile:9-10](file://Makefile#L9-L10)
|
||
|
||
### 调试工具与技巧
|
||
- 日志:开发环境开启彩色日志,生产环境使用 ISO 时间与生产配置;关注请求耗时与错误堆栈。
|
||
- 请求追踪:通过 Request ID 关联一次请求在多组件中的日志。
|
||
- 网络抓包:使用 curl/Postman 验证路由与参数;检查 CORS 与状态码。
|
||
- 性能剖析:使用 pprof 分析 CPU/内存热点;结合日志定位慢查询。
|
||
|
||
章节来源
|
||
- [pkg/logger/logger.go:8-19](file://pkg/logger/logger.go#L8-L19)
|
||
- [internal/middleware/request_id.go:10-30](file://internal/middleware/request_id.go#L10-L30)
|
||
- [internal/middleware/logger.go:10-45](file://internal/middleware/logger.go#L10-L45)
|
||
|
||
### 扩展开发与中间件
|
||
- 插件机制:当前未内置插件框架,建议通过接口抽象与依赖注入的方式扩展功能(如鉴权、限流)。
|
||
- 自定义中间件:遵循 gin.HandlerFunc 签名,在中间件中只做横切关注点,避免业务逻辑。
|
||
- 路由扩展:在 router 分组下新增子路由,注册处理器并确保统一响应。
|
||
|
||
章节来源
|
||
- [internal/router/router.go:14-41](file://internal/router/router.go#L14-L41)
|
||
- [internal/middleware/logger.go:10-45](file://internal/middleware/logger.go#L10-L45)
|
||
|
||
### 重构与优化建议
|
||
- 代码重构:拆分过长函数、消除重复代码、统一错误处理与日志风格。
|
||
- 性能优化:索引优化、查询去 N+1、连接池参数调优、缓存热点数据。
|
||
- 安全加固:强制 HTTPS、限制请求大小、参数校验、敏感日志脱敏。
|
||
|
||
### 开发环境配置与团队协作
|
||
- 环境变量:开发使用 .env,生产通过环境变量注入;数据库密码必须来自环境。
|
||
- 启动方式:使用 make run 或 go run ./cmd/server;构建产物位于 bin/server。
|
||
- 团队协作:提交前执行 go test 与 go mod tidy;PR 需要至少一名 reviewer 通过。
|
||
|
||
章节来源
|
||
- [README.md:21-81](file://README.md#L21-L81)
|
||
- [Makefile:3-7](file://Makefile#L3-L7) |