553 lines
16 KiB
Markdown
553 lines
16 KiB
Markdown
# Rust 后端 - 改进计划
|
||
|
||
## 一、代码质量与架构改进
|
||
|
||
### 1.1 代码组织问题
|
||
- [x] **所有路由处理器都在 main.rs 中** ✅
|
||
- 改进:将 handler 函数按功能模块拆分到 `handlers/` 目录
|
||
- 目录结构:
|
||
- `handlers/auth.rs` - 登录相关
|
||
- `handlers/weather.rs` - 天气数据 CRUD
|
||
- `handlers/user.rs` - 用户相关
|
||
- `handlers/admin.rs` - 管理员功能
|
||
- `handlers/health.rs` - 健康检查
|
||
- `handlers/static_files.rs` - 静态文件服务
|
||
- 完成时间:2026-04-15
|
||
- 附加:发现并修复静态文件被 JWT middleware 拦截的问题(路由顺序)
|
||
|
||
- [ ] **config.rs 是死代码**
|
||
- 现状:AGENTS.md 中提到 config.rs 未被使用
|
||
- 改进:要么启用配置管理,要么删除该文件
|
||
- 影响:减少代码混淆
|
||
|
||
### 1.2 数据库操作优化
|
||
- [ ] **重复查询问题**
|
||
- 位置:`insert_weather_data` 中多次查询用户信息
|
||
- 改进:合并查询或使用缓存
|
||
- 影响:减少数据库负载
|
||
|
||
- [ ] **缺少数据库索引**
|
||
- 现状:未见索引定义
|
||
- 改进:添加常用查询字段索引
|
||
```sql
|
||
CREATE INDEX idx_weather_data_user_id ON weather_data(user_id);
|
||
CREATE INDEX idx_weather_data_date ON weather_data(date);
|
||
CREATE INDEX idx_users_openid ON users(openid);
|
||
```
|
||
|
||
### 1.3 错误处理改进
|
||
- [x] **错误响应格式不统一** ✅
|
||
- 现状:部分返回 `ErrorResponse`,部分返回 JSON 字符串
|
||
- 改进:统一使用 `ErrorResponse` 结构体
|
||
- 彰响:前端解析更一致
|
||
- 完成时间:2026-04-15
|
||
|
||
- [x] **错误信息暴露过多** ✅
|
||
- 现状:部分错误直接返回数据库错误信息
|
||
- 改进:区分用户友好错误和开发者错误
|
||
- 影响:安全性提升
|
||
- 完成时间:2026-04-15
|
||
- 修改:移除所有 `errmsg: Some(e.to_string())`,错误详情只记录到日志
|
||
|
||
## 二、安全性改进
|
||
|
||
### 2.1 认证安全
|
||
- [ ] **缺少请求频率限制** ⚠️
|
||
- 风险:API 可能被滥用或遭受暴力攻击
|
||
- 改进:添加 Rate Limiting 中间件
|
||
- 配置:
|
||
- 登录接口:5 次/分钟
|
||
- 数据上传:30 次/分钟
|
||
- 查询接口:100 次/分钟
|
||
- **状态**:actix-ratelimit 0.3.1 与 actix-web 4.x 不兼容(Transform trait 问题)
|
||
- **备选方案**:
|
||
1. `actix-web-lab` - 社区维护的中间件库
|
||
2. 手动实现 - 使用 `std::collections::HashMap` 记录 IP 请求数
|
||
3. Nginx/网关层限流
|
||
|
||
- [ ] **缺少 CSRF 防护**
|
||
- 风险:跨站请求伪造攻击
|
||
- 改进:添加 CSRF Token 验证
|
||
- 实现:对于状态变更操作验证 Token
|
||
|
||
- [ ] **JWT Secret 管理**
|
||
- 现状:明文存储在环境变量
|
||
- 改进:使用密钥管理服务(如 AWS Secrets Manager)
|
||
- 影响:提高密钥安全性
|
||
|
||
### 2.2 数据安全
|
||
- [ ] **数据库连接字符串明文存储**
|
||
- 位置:`.env` 文件
|
||
- 改进:使用连接字符串加密或密钥管理
|
||
- 影响:防止凭证泄露
|
||
|
||
- [ ] **缺少敏感数据加密**
|
||
- 现状:用户信息明文存储
|
||
- 改进:对敏感字段加密存储
|
||
- 字段:手机号、姓名等
|
||
|
||
- [ ] **缺少审计日志**
|
||
- 需求:记录关键操作日志
|
||
- 实现:添加审计日志表和中间件
|
||
- 记录:登录、数据修改、管理员操作
|
||
|
||
### 2.3 输入验证
|
||
- [ ] **后端输入验证不完整**
|
||
- 现状:部分依赖前端验证
|
||
- 改进:添加完整的请求验证
|
||
- 实现:使用 `validator` crate
|
||
|
||
## 三、性能优化
|
||
|
||
### 3.1 数据库性能
|
||
- [ ] **缺少连接池监控**
|
||
- 现状:连接池配置固定
|
||
- 改进:添加连接池监控和动态调整
|
||
- 指标:连接数、等待时间、超时次数
|
||
|
||
- [ ] **缺少查询缓存**
|
||
- 场景:用户信息、配置数据
|
||
- 改进:添加 Redis 缓存层
|
||
- 策略:用户信息缓存 5 分钟,配置数据缓存 1 小时
|
||
|
||
- [ ] **无读写分离支持**
|
||
- 需求:高并发场景下的性能优化
|
||
- 改进:支持主从数据库配置
|
||
- 实现:使用 sqlx 的多数据源支持
|
||
|
||
### 3.2 API 性能
|
||
- [ ] **无响应压缩**
|
||
- 现状:响应未压缩
|
||
- 改进:添加 gzip 压缩中间件
|
||
- 实现:使用 `actix-web` 的压缩功能
|
||
|
||
- [ ] **缺少 API 缓存**
|
||
- 场景:天气数据列表查询
|
||
- 改进:添加 HTTP 缓存头
|
||
- 实现:`Cache-Control`、`ETag` 等
|
||
|
||
- [ ] **无 CDN 支持**
|
||
- 场景:静态资源分发
|
||
- 改进:配置 CDN 加速
|
||
- 资源:CSS、JS、图片、字体
|
||
|
||
## 四、功能完整性改进
|
||
|
||
### 4.1 API 功能扩展
|
||
- [ ] **缺少批量操作接口**
|
||
- 需求:批量删除、批量查询
|
||
- 实现:添加批量操作端点
|
||
- 接口:`POST /weather/batch-delete`、`POST /weather/batch-query`
|
||
|
||
- [ ] **无数据导出格式支持**
|
||
- 需求:支持 CSV、Excel 导出
|
||
- 实现:添加导出端点
|
||
- 接口:`GET /weather/export?format=csv`
|
||
|
||
- [ ] **缺少搜索和过滤功能**
|
||
- 需求:按日期、标题、地点搜索
|
||
- 实现:添加搜索参数
|
||
- 参数:`?keyword=xxx&startDate=xxx&endDate=xxx`
|
||
|
||
### 4.2 用户功能
|
||
- [ ] **缺少用户活动统计**
|
||
- 需求:用户使用情况分析
|
||
- 实现:添加统计接口
|
||
- 数据:登录次数、数据上传量、最后活跃时间
|
||
|
||
- [ ] **无用户偏好设置**
|
||
- 需求:保存用户偏好(如默认区域类型)
|
||
- 实现:添加用户设置表
|
||
- 接口:`GET/PUT /api/user/preferences`
|
||
|
||
## 五、开发体验改进
|
||
|
||
### 5.1 测试覆盖
|
||
- [ ] **仅有一个基础编译测试**
|
||
- 现状:`tests/integration_test.rs` 只有 `assert_eq!(2 + 2, 4)`
|
||
- 改进:添加完整的测试套件
|
||
- 类型:
|
||
- 单元测试:工具函数、数据结构
|
||
- 集成测试:API 端点
|
||
- 数据库测试:CRUD 操作
|
||
|
||
- [ ] **缺少 API 测试**
|
||
- 需求:验证 API 行为
|
||
- 实现:使用 `actix-web` 的测试工具
|
||
- 覆盖:正常流程、异常情况、边界条件
|
||
|
||
### 5.2 文档完善
|
||
- [ ] **无 API 文档**
|
||
- 需求:接口文档
|
||
- 实现:使用 OpenAPI/Swagger
|
||
- 工具:`utoipa` crate
|
||
|
||
- [ ] **缺少部署文档**
|
||
- 内容:环境要求、配置说明、部署步骤
|
||
- 形式:`DEPLOYMENT.md` 文件
|
||
|
||
- [ ] **无变更日志**
|
||
- 内容:版本更新记录
|
||
- 形式:`CHANGELOG.md` 文件
|
||
|
||
### 5.3 开发工具
|
||
- [ ] **缺少代码质量工具**
|
||
- 工具:`clippy`、`rustfmt`
|
||
- 配置:`.clippy.toml`、`rustfmt.toml`
|
||
- 集成:CI/CD 流程
|
||
|
||
- [ ] **无热重载开发**
|
||
- 需求:开发时自动重载
|
||
- 实现:使用 `cargo-watch`
|
||
- 命令:`cargo watch -x run`
|
||
|
||
## 六、监控与运维
|
||
|
||
### 6.1 日志系统
|
||
- [x] **日志格式不统一** ✅
|
||
- 现状:部分使用 `log` 宏,部分使用 `println`
|
||
- 改进:统一使用结构化日志
|
||
- 实现:使用 `tracing` crate
|
||
- 完成时间:2026-04-15
|
||
- 修改文件:Cargo.toml, src/main.rs, src/config.rs
|
||
|
||
- [x] **无日志聚合** ✅
|
||
- 需求:集中式日志管理
|
||
- 实现:配置日志收集器(如 ELK Stack)
|
||
- 格式:JSON 格式便于解析
|
||
- 状态:✅ 已完成(JSON + 文件轮转,2026-04-15)
|
||
|
||
- [ ] **缺少性能指标收集** ⚠️
|
||
- 需求:API 响应时间、错误率等
|
||
- 实现:添加 Prometheus 指标
|
||
- **状态**:actix-web-prom 与当前架构不兼容(ServiceFactory Response 类型冲突)
|
||
- **备选方案**:
|
||
1. `actix-web-lab` - 社区维护的中间件库
|
||
2. 手动实现 - 在代码中直接使用 `std::sync::atomic` 收集请求计数
|
||
3. Nginx 层收集 - 反向代理层已有 access log
|
||
|
||
### 6.2 告警机制
|
||
- [ ] **无异常告警**
|
||
- 需求:系统异常时通知
|
||
- 实现:集成告警服务
|
||
- 渠道:邮件、钉钉、企业微信
|
||
|
||
- [ ] **缺少资源监控**
|
||
- 需求:CPU、内存、磁盘监控
|
||
- 实现:使用系统监控工具
|
||
- 工具:Prometheus + Grafana
|
||
|
||
### 6.3 健康检查
|
||
- [x] **缺少健康检查接口** ✅
|
||
- 需求:负载均衡器健康检查
|
||
- 实现:添加 `/health` 端点
|
||
- 检查:数据库连接、服务状态
|
||
- 完成时间:2026-04-15
|
||
|
||
## 七、部署改进
|
||
|
||
### 7.1 部署流程
|
||
- [ ] **部署脚本功能简单**
|
||
- 现状:仅支持基本的编译、上传、重启
|
||
- 改进:添加回滚、备份、验证功能
|
||
- 实现:增强 `deploy.sh` 脚本
|
||
|
||
- [ ] **无蓝绿部署或滚动更新**
|
||
- 需求:零停机部署
|
||
- 实现:使用 Docker + Kubernetes
|
||
- 或者:Nginx 负载均衡 + 多实例
|
||
|
||
### 7.2 容器化
|
||
- [ ] **缺少 Docker 支持**
|
||
- 需求:容器化部署
|
||
- 实现:添加 `Dockerfile` 和 `docker-compose.yml`
|
||
- 优势:环境一致性、易于扩展
|
||
|
||
### 7.3 CI/CD
|
||
- [ ] **无自动化流程**
|
||
- 需求:自动测试、构建、部署
|
||
- 实现:配置 GitHub Actions 或 Gitea Actions
|
||
- 流程:代码提交 → 测试 → 构建 → 部署
|
||
|
||
## 八、技术债务
|
||
|
||
### 8.1 高优先级
|
||
1. [ ] **拆分 main.rs 中的路由处理器**
|
||
- 影响:代码可维护性
|
||
- 工作量:中等
|
||
|
||
2. [ ] **添加请求频率限制**
|
||
- 影响:安全性
|
||
- 工作量:小
|
||
|
||
3. [ ] **统一错误响应格式**
|
||
- 影响:前后端对接
|
||
- 工作量:小
|
||
|
||
4. [ ] **添加数据库索引**
|
||
- 影响:性能
|
||
- 工作量:小
|
||
|
||
### 8.2 中优先级
|
||
1. [ ] **添加单元测试和集成测试**
|
||
- 影响:代码质量
|
||
- 工作量:大
|
||
|
||
2. [ ] **实现 API 文档(OpenAPI)**
|
||
- 影响:开发体验
|
||
- 工作量:中等
|
||
|
||
3. [ ] **添加结构化日志**
|
||
- 影响:运维
|
||
- 工作量:中等
|
||
|
||
4. [ ] **优化数据库查询**
|
||
- 影响:性能
|
||
- 工作量:中等
|
||
|
||
### 8.3 低优先级
|
||
1. [ ] **实现 Redis 缓存**
|
||
- 影响:性能
|
||
- 工作量:大
|
||
|
||
2. [ ] **容器化部署**
|
||
- 影响:部署流程
|
||
- 工作量:中等
|
||
|
||
3. [ ] **添加监控告警**
|
||
- 影响:运维
|
||
- 工作量:大
|
||
|
||
4. [ ] **实现 CI/CD**
|
||
- 影响:开发效率
|
||
- 工作量:中等
|
||
|
||
## 十、缺少环境区分机制
|
||
|
||
### 问题描述
|
||
|
||
当前后端项目未区分生产环境和开发/测试环境,所有配置混在一个 `.env` 文件中。
|
||
|
||
**现状分析**:
|
||
|
||
| 配置项 | 当前做法 | 问题 |
|
||
|--------|----------|------|
|
||
| DATABASE_URL | 硬编码生产数据库地址 | 开发/测试时无法切换到本地或测试数据库 |
|
||
| JWT_SECRET | 混在 .env 中 | 开发环境使用弱密钥存在安全隐患 |
|
||
| RUST_LOG | 统一设置为 `info` | 开发时需要 `debug` 级别日志 |
|
||
| APP_VERSION | 在 .env 和 Cargo.toml 两处定义 | 版本不一致 |
|
||
|
||
**.env 当前内容**:
|
||
```bash
|
||
DATABASE_URL=postgres://milkydata:***@154.37.213.24:5432/milkydata
|
||
WECHAT_APPID="wx5b00eb90621802f7"
|
||
WECHAT_SECRET="494efc...9bfd"
|
||
JWT_SECRET="your_s..._key"
|
||
SSL_KEY_PATH=/etc/ssl/private/private.key
|
||
SSL_CERT_PATH=/etc/ssl/certs/full_chain.pem
|
||
RUST_LOG=info
|
||
APP_VERSION="0.2.0"
|
||
FREE_USER_DATA_LIMIT=20
|
||
```
|
||
|
||
### 影响
|
||
|
||
- 开发时连接生产数据库,有误操作风险
|
||
- 测试时无法使用独立的测试数据
|
||
- 切换环境需要手动修改配置,容易出错
|
||
- 生产配置泄露到代码仓库(.env 通常被 gitignore,但部署时容易混淆)
|
||
|
||
### 解决方案
|
||
|
||
#### 方案一:使用 config crate(推荐)
|
||
|
||
**添加依赖**:
|
||
```toml
|
||
# Cargo.toml
|
||
[dependencies]
|
||
config = "0.14"
|
||
serde = { version = "1.0", features = ["derive"] }
|
||
```
|
||
|
||
**目录结构**:
|
||
```
|
||
rust-backend/
|
||
├── config/
|
||
│ ├── default.toml # 默认配置(开发)
|
||
│ ├── development.toml
|
||
│ └── production.toml
|
||
├── .env # 本地敏感配置(加入 .gitignore)
|
||
└── .env.example # 配置模板(提交到仓库)
|
||
```
|
||
|
||
**default.toml(开发/测试默认)**:
|
||
```toml
|
||
database_url = "postgres://milkydata:password@localhost:5432/milkydata_dev"
|
||
wechat_appid = "wx_test_appid"
|
||
wechat_secret = "test_secret"
|
||
jwt_secret = "dev-only-secret-change-in-production"
|
||
ssl_key_path = ""
|
||
ssl_cert_path = ""
|
||
rust_log = "debug"
|
||
app_version = "0.2.3"
|
||
environment = "development"
|
||
free_user_data_limit = 100
|
||
server_host = "0.0.0.0"
|
||
server_port = 8080
|
||
```
|
||
|
||
**production.toml(生产环境)**:
|
||
```toml
|
||
database_url = "postgres://milkydata:***@154.37.213.24:5432/milkydata"
|
||
wechat_appid = "wx5b00eb90621802f7"
|
||
wechat_secret = "***"
|
||
jwt_secret = "***"
|
||
ssl_key_path = "/etc/ssl/private/private.key"
|
||
ssl_cert_path = "/etc/ssl/certs/full_chain.pem"
|
||
rust_log = "info"
|
||
app_version = "0.2.3"
|
||
environment = "production"
|
||
free_user_data_limit = 20
|
||
server_host = "0.0.0.0"
|
||
server_port = 8080
|
||
```
|
||
|
||
**配置加载逻辑**:
|
||
|
||
```rust
|
||
// src/config.rs
|
||
use config::{Config, ConfigError, File};
|
||
use serde::Deserialize;
|
||
|
||
#[derive(Debug, Deserialize, Clone)]
|
||
pub struct AppConfig {
|
||
pub database_url: String,
|
||
pub wechat_appid: String,
|
||
pub wechat_secret: String,
|
||
pub jwt_secret: String,
|
||
pub ssl_key_path: String,
|
||
pub ssl_cert_path: String,
|
||
pub rust_log: String,
|
||
pub app_version: String,
|
||
pub environment: String,
|
||
pub free_user_data_limit: i32,
|
||
pub server_host: String,
|
||
pub server_port: u16,
|
||
}
|
||
|
||
impl AppConfig {
|
||
pub fn load() -> Result<Self, ConfigError> {
|
||
// 从环境变量读取当前环境,默认为 development
|
||
let env = std::env::var("APP_ENV").unwrap_or_else(|_| "development".into());
|
||
|
||
let config = Config::builder()
|
||
// 1. 先加载默认配置
|
||
.add_source(File::with_name("config/default"))
|
||
// 2. 再加载当前环境配置(覆盖默认值)
|
||
.add_source(File::with_name(&format!("config/{}", env)).required(false))
|
||
// 3. 最后从环境变量加载(最高优先级)
|
||
.add_source(config::Environment::with_prefix("APP"))
|
||
.build()?;
|
||
|
||
config.try_deserialize()
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 方案二:简化方案(最小改动)
|
||
|
||
保持现有 `.env` 结构不变,通过 `APP_ENV` 环境变量和 `.env.development` / `.env.production` 文件区分:
|
||
|
||
**`.env.example`(提交到仓库的配置模板)**:
|
||
```bash
|
||
# 必填配置
|
||
DATABASE_URL=postgres://user:pass@host:port/dbname
|
||
JWT_SECRET=your-secret-key
|
||
WECHAT_APPID=your-wechat-appid
|
||
WECHAT_SECRET=your-wechat-secret
|
||
|
||
# 可选配置(带默认值)
|
||
APP_ENV=development
|
||
RUST_LOG=info
|
||
APP_VERSION=0.2.3
|
||
FREE_USER_DATA_LIMIT=20
|
||
SSL_KEY_PATH=
|
||
SSL_CERT_PATH=
|
||
```
|
||
|
||
**部署脚本增强**:
|
||
|
||
```bash
|
||
#!/bin/bash
|
||
# deploy.sh
|
||
|
||
# 接收环境参数
|
||
ENV=${1:-production}
|
||
|
||
# 根据环境加载不同配置
|
||
if [ "$ENV" = "development" ]; then
|
||
source .env.development
|
||
elif [ "$ENV" = "production" ]; then
|
||
source .env.production
|
||
fi
|
||
|
||
# 构建和部署...
|
||
```
|
||
|
||
### 环境切换操作指南
|
||
|
||
| 场景 | 操作方法 |
|
||
|------|----------|
|
||
| 本地开发 | `APP_ENV=development cargo run`,连接本地数据库 |
|
||
| 测试服务器部署 | `APP_ENV=development ./deploy.sh` |
|
||
| 生产环境部署 | `APP_ENV=production ./deploy.sh` 或默认 `./deploy.sh` |
|
||
| 查看当前环境 | 启动后访问 `/health` 接口或检查日志 |
|
||
|
||
### 实施步骤
|
||
|
||
**第一阶段(最小改动)**:
|
||
1. 创建 `.env.example` 配置模板,移除敏感信息
|
||
2. 在 `deploy.sh` 中添加 `APP_ENV` 参数支持
|
||
3. 创建 `.env.development` 本地开发配置(可选加入 .gitignore)
|
||
|
||
**第二阶段(推荐)**:
|
||
1. 添加 `config` crate 依赖
|
||
2. 创建 `config/default.toml` 和 `config/production.toml`
|
||
3. 重构 `config.rs` 使用 config crate
|
||
4. 更新 `deploy.sh` 使用新的配置加载方式
|
||
|
||
### 相关改进项
|
||
|
||
- 本改进与"前后端版本统一管理"(改进路线图 P1)可合并实施
|
||
- 本改进与"拆分 main.rs 路由处理器"(改进路线图 P1)有协同效应
|
||
|
||
---
|
||
|
||
## 十一、检查清单
|
||
|
||
### 代码提交前检查
|
||
- [ ] 通过 `cargo clippy` 检查
|
||
- [ ] 通过 `cargo fmt` 格式化
|
||
- [ ] 单元测试通过
|
||
- [ ] 无硬编码的敏感信息
|
||
- [ ] 配置文件不包含实际密钥
|
||
|
||
### 部署前检查
|
||
- [ ] 数据库迁移脚本准备
|
||
- [ ] 环境变量配置检查
|
||
- [ ] 备份当前版本
|
||
- [ ] 健康检查接口正常
|
||
- [ ] 确认目标环境的配置正确
|
||
|
||
### 安全检查
|
||
- [ ] 输入验证完整
|
||
- [ ] 错误信息不暴露敏感数据
|
||
- [ ] 认证和授权正确
|
||
- [ ] 日志不记录敏感信息
|
||
- [ ] 生产环境使用强密钥
|
||
|
||
---
|
||
|
||
**最后更新**:2026-04-14
|
||
**维护者**:milky
|