Files
Meshray-Manager/docs/DDNS 双模式实现完成报告.md
2026-06-30 15:14:37 +08:00

430 lines
11 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# DDNS 双模式实现完成报告
## 📋 实现概述
本次实现完成了 DDNS(动态 DNS)的**双模式架构**,将 DDNS 配置与使用完全解耦,支持两种不同的应用场景:
1. **基础设施配置模式** - 仅配置 DNS 服务商对接信息
2. **全功能 DDNS 服务模式** - 创建完整的 DNS 记录,支持内网穿透等应用
---
## ✅ 已完成的工作
### 1. 前端实现
#### 修改的文件
- `web/src/views/Service/List.vue`
#### 核心功能
✅ Tab 4 改名为"增强"(从"服务市场"
✅ DDNS 表单支持两种模式切换
✅ 基础设施模式:只配置服务商信息
✅ 全功能模式:支持 A/AAAA/TXT/CNAME 记录类型
✅ 根据记录类型动态显示字段
✅ 表单验证规则区分模式
✅ 增强页展示服务卡片
✅ 点击卡片自动填充表单
#### UI 组件
```vue
// 模式选择
<el-radio-group v-model="formData.config_mode">
<el-radio value="infrastructure">🏗️ 基础设施配置</el-radio>
<el-radio value="fullservice">🚀 全功能 DDNS 服务</el-radio>
</el-radio-group>
// 基础设施模式字段
- DNS 服务商
- 根域名
- API Token / AccessKey
// 全功能模式字段
- 选择 DDNS 配置级联选择
- 记录类型A/AAAA/TXT/CNAME
- 主机记录A/AAAA
- 目标 IPA/AAAA
- 检测端口A/AAAA
- TXT 记录名称和值TXT
- 目标域名CNAME
- TTL
```
---
### 2. 后端实现
#### 修改的文件
- `internal/model/models.go` - 数据模型
- `internal/service/service.go` - Service 层
#### 数据模型扩展
`Service` 模型中添加了以下字段:
```go
// DDNS 全功能模式字段
ConfigMode string `gorm:"type:varchar(16);default:'infrastructure'" json:"config_mode"`
DDNSConfigID string `gorm:"type:varchar(36)" json:"ddns_config_id,omitempty"`
Subdomain string `gorm:"type:varchar(255)" json:"subdomain,omitempty"`
TargetIP string `gorm:"type:varchar(64)" json:"target_ip,omitempty"`
TXTRecordName string `gorm:"type:varchar(255)" json:"txt_record_name,omitempty"`
TXTValue string `gorm:"type:text" json:"txt_value,omitempty"`
CNAMETarget string `gorm:"type:varchar(255)" json:"cname_target,omitempty"`
TTL int `gorm:"default:600" json:"ttl,omitempty"`
```
#### Service 层校验逻辑
**基础设施模式校验**
```go
if req.Type == "DDNS" && req.ConfigMode == "infrastructure" {
// 校验服务商
if req.Provider == "" {
return nil, errors.New("请选择 DNS 服务商")
}
// 校验域名
if req.Domain == "" {
return nil, errors.New("请输入根域名")
}
// 根据服务商校验认证信息
switch req.Provider {
case "cloudflare":
if req.Token == "" {
return nil, errors.New("请输入 API Token")
}
case "aliyun":
if req.AuthUsername == "" || req.AuthPassword == "" {
return nil, errors.New("请输入 AccessKey ID 和 Secret")
}
case "tencent":
if req.AuthUsername == "" || req.AuthPassword == "" {
return nil, errors.New("请输入 SecretId 和 SecretKey")
}
}
}
```
**全功能模式校验**
```go
if req.Type == "DDNS" && req.ConfigMode == "fullservice" {
// 校验关联的 DDNS 配置
if req.DDNSConfigID == "" {
return nil, errors.New("请选择 DDNS 配置")
}
// 校验记录类型
if req.RecordType == "" {
return nil, errors.New("请选择记录类型")
}
// 根据记录类型校验具体字段
switch req.RecordType {
case "A", "AAAA":
if req.Subdomain == "" {
return nil, errors.New("请输入主机记录")
}
if req.TargetIP == "" {
return nil, errors.New("请输入目标 IP")
}
if req.Port <= 0 {
return nil, errors.New("请输入检测端口")
}
case "TXT":
if req.TXTRecordName == "" {
return nil, errors.New("请输入 TXT 记录名称")
}
if req.TXTValue == "" {
return nil, errors.New("请输入 TXT 记录值")
}
case "CNAME":
if req.CNAMETarget == "" {
return nil, errors.New("请输入目标域名")
}
}
}
```
---
### 3. 文档
#### 创建的文档
`DDNS 双模式架构设计.md` - 详细的设计文档
`DDNS 双模式功能测试指南.md` - 完整的测试用例
`DDNS 双模式实现完成报告.md` - 本文档
---
## 🎯 用户使用流程
### 场景 1:组网同步 MeshSeed(使用基础设施模式)
```
步骤 1: 配置 DDNS 服务商
├─ 访问:服务管理 → Tab 3 "DDNS"
├─ 点击:"添加 DDNS"
├─ 配置模式:选择"基础设施配置"
├─ 填写:
│ ├─ DNS 服务商:Cloudflare
│ ├─ 根域名:example.com
│ └─ API Token: cf_abc123...
└─ 提交 → 保存配置
步骤 2: 创建组网时选用
├─ 访问:组网管理 → 创建网络
├─ 基础信息 → 填写网络名称
├─ DDNS 同步配置 → 启用
├─ 选择 DDNS 服务:选择步骤 1 的配置
├─ TXT 记录前缀:自动生成 / 自定义
└─ 提交 → 系统自动创建 TXT 记录
结果:
- TXT 记录名:_meshray.{短 ID}.example.com
- 记录值:加密的 MeshSeed 配置
- 设备加入时自动读取
```
### 场景 2:NAS 内网穿透(使用全功能模式)
```
前置条件:已在 Tab 3 配置 DDNS 服务商
步骤 1: 创建 DDNS 内网穿透服务
├─ 访问:服务管理 → Tab 4 "增强"
├─ 点击:"DDNS 内网穿透"卡片
├─ 配置模式:自动选择"全功能 DDNS 服务"
├─ 填写:
│ ├─ 选择 DDNS 配置:Cloudflare (example.com)
│ ├─ 记录类型:AAAA (IPv6)
│ ├─ 主机记录:nas
│ ├─ 目标 IP: ::ffff:192.168.1.100
│ ├─ 检测端口:80
│ └─ TTL: 600 (10 分钟)
└─ 提交 → 创建 DNS 记录
步骤 2: 系统自动维护
├─ 定时检测本地 IPv6 地址
├─ 如果 IP 变化 → 调用 Cloudflare API 更新
├─ 保持 nas.example.com 始终指向最新 IP
└─ 用户可通过域名随时访问
结果:
- 完整域名:nas.example.com
- 记录类型:AAAA (IPv6)
- 目标:::ffff:192.168.1.100
- 自动更新: enabled
```
---
## 📊 数据库表结构变更
### Service 表新增字段
| 字段名 | 类型 | 默认值 | 说明 |
|--------|------|--------|------|
| `config_mode` | varchar(16) | 'infrastructure' | 配置模式:infrastructure \| fullservice |
| `ddns_config_id` | varchar(36) | NULL | 关联的 DDNS 配置 ID(外键) |
| `subdomain` | varchar(255) | NULL | 主机记录(子域名) |
| `target_ip` | varchar(64) | NULL | 目标 IP 地址 |
| `txt_record_name` | varchar(255) | NULL | TXT 记录名称 |
| `txt_value` | text | NULL | TXT 记录值 |
| `cname_target` | varchar(255) | NULL | CNAME 目标域名 |
| `ttl` | int | 600 | TTL(秒) |
---
## 🔧 技术实现细节
### 1. 前端动态表单
**模式切换逻辑**
```javascript
// 监听 config_mode 变化
watch(() => formData.value.config_mode, (newMode) => {
if (newMode === 'infrastructure') {
// 清空全功能模式字段
formData.value.ddns_config_id = ''
formData.value.subdomain = ''
formData.value.target_ip = ''
// ...
} else if (newMode === 'fullservice') {
// 清空基础设施模式字段
formData.value.provider = ''
formData.value.domain = ''
formData.value.token = ''
// ...
}
})
```
**条件字段显示**
```vue
<!-- 基础设施模式 -->
<template v-if="formData.config_mode === 'infrastructure'">
<el-form-item label="DNS 服务商" prop="provider">
<el-select v-model="formData.provider">
<el-option label="阿里云 DNS" value="aliyun" />
<el-option label="Cloudflare" value="cloudflare" />
</el-select>
</el-form-item>
</template>
<!-- 全功能模式 -->
<template v-else-if="formData.config_mode === 'fullservice'">
<el-form-item label="选择 DDNS 配置" prop="ddns_config_id">
<el-select v-model="formData.ddns_config_id" filterable>
<el-option
v-for="config in ddnsConfigs"
:key="config.id"
:label="`${config.name} (${config.config?.domain})`"
:value="config.id"
/>
</el-select>
</el-form-item>
</template>
```
### 2. 后端校验链
```
API Handler (CreateService)
Service 层 (CreateService)
类型检查:req.Type == "DDNS"
模式检查:req.ConfigMode
├─ infrastructure → 校验服务商 + 认证信息
└─ fullservice → 校验关联配置 + 记录类型 + 具体字段
数据库保存
```
### 3. 数据关联关系
```
全功能 DDNS 服务
ddns_config_id (外键)
基础设施 DDNS 配置
解析出:Provider + Domain + API Token
调用 DNS 服务商 API
创建/更新 DNS 记录
```
---
## ✅ 验证清单
### 前端验证
- [x] Tab 4 显示为"增强"
- [x] Tab 3 文案正确
- [x] DDNS 表单有两种模式选项
- [x] 基础设施模式字段显示正确
- [x] 全功能模式字段显示正确
- [x] 记录类型切换时字段联动
- [x] 表单验证规则正确
- [x] 增强页服务卡片显示
- [x] 点击卡片行为正确
- [x] 无控制台错误
### 后端验证
- [x] 数据模型包含所有新字段
- [x] Service 层校验逻辑完整
- [x] 编译无错误
- [x] 服务正常启动
---
## 🚀 下一步工作
### 待实现的功能
#### 1. DDNS 全功能服务的实际 DNS 操作
**优先级**: P0
**内容**:
- 集成 libdns 库
- 实现 DNS 记录的 CRUD 操作
- 支持各云服务商的 API 调用
- 实现 IP 检测和自动更新
**涉及文件**:
- `internal/service/ddns_full.go` (新建)
- `internal/dnsprovider/` (新建目录)
#### 2. 后台任务调度
**优先级**: P1
**内容**:
- 定时检测 IP 变化
- 批量更新 DNS 记录
- 失败重试机制
- 告警通知
**涉及文件**:
- `internal/scheduler/ddns_updater.go` (新建)
#### 3. 前后端联调测试
**优先级**: P1
**内容**:
- 按照测试指南逐项验证
- 测试真实的 DNS 服务商 API
- 验证 IP 检测和更新逻辑
- 性能测试和压力测试
**涉及文件**:
- `DDNS 双模式功能测试指南.md`
#### 4. 数据库迁移
**优先级**: P2
**内容**:
- 添加新字段的 Migration
- 数据兼容性处理
- 旧数据升级
**涉及文件**:
- `internal/store/sqlite/migrate.go`
---
## 📝 注意事项
### 1. 安全性
- ✅ API Token/AccessKey 等敏感信息需要加密存储
- ✅ 数据库字段使用 `password` 标签避免返回敏感数据
- ✅ 日志中需要脱敏处理
### 2. 性能优化
- ⚠️ DDNS 配置列表需要缓存,避免频繁查询
- ⚠️ IP 检测需要使用多个服务交叉验证
- ⚠️ DNS 更新需要实现幂等性,避免重复调用
### 3. 错误处理
- ⚠️ DNS API 调用失败需要有重试机制
- ⚠️ 网络异常需要友好提示用户
- ⚠️ 记录详细的操作日志便于排查
---
## 🎉 总结
本次实现完成了 DDNS 双模式架构的**前后端基础框架**:
**前端**:完整的 UI 交互、表单验证、模式切换
**后端**:数据模型、校验逻辑、API 接口
**文档**:架构设计、测试指南、实现报告
**当前状态**:基础框架完成,可以进行真实 DNS 操作的开发了。
**下一步重点**:集成 libdns 库,实现真实的 DNS 记录创建和更新功能。
---
**实现日期**: 2026-03-20
**实现人员**: AI Assistant
**实现状态**: ✅ 基础框架完成,等待 DNS 操作集成