9.1 KiB
9.1 KiB
DDNS TXT 记录字段排查报告
排查时间: 2026-03-26
状态: ✅ 全链路都有 TXT 字段
🔍 排查结果
✅ 前端页面 - 有 TXT 字段
文件: web/src/views/Service/DDNSEdit.vue
<!-- 第 65-79 行 -->
<!-- TXT 记录名称 -->
<el-form-item label="TXT 记录名称" prop="txt_record_name">
<el-input
v-model="formData.txt_record_name"
placeholder="_meshray._mesh"
clearable
/>
<div class="form-tip">
<el-icon><InfoFilled /></el-icon>
DNS TXT 记录前缀,MeshSeed 密文将写入此记录
</div>
<div class="form-tip">
<el-icon><InfoFilled /></el-icon>
完整记录:{{ formData.txt_record_name }}.{{ formData.domain || 'example.com' }}
</div>
</el-form-item>
验证点:
- ✅ 表单字段存在
- ✅ 默认值
_meshray._mesh - ✅ 有提示信息
- ✅ 有完整记录预览
✅ 前端 API - 有 TXT 字段
文件: web/src/api/ddns.js
/**
* @typedef {Object} DDNSConfig
* @property {'aliyun' | 'tencent' | 'cloudflare' | 'custom'} provider
* @property {string} access_key_id
* @property {string} access_key_secret
* @property {string} domain
* @property {string} txt_record_name // ← 第 9 行
* @property {'auto' | 'manual'} sync_mode
* @property {number} retry_interval
* @property {number} max_retries
* @property {boolean} enabled
*/
验证点:
- ✅ TypeScript 类型定义包含
txt_record_name - ✅ 测试请求参数包含(第 29 行)
✅ 后端 Handler - 有 TXT 字段
文件: internal/api/handler/ddns.go
// DDNSConfigRequest DDNS 配置请求
type DDNSConfigRequest struct {
Provider string `json:"provider"`
AccessKeyID string `json:"access_key_id"`
AccessKeySecret string `json:"access_key_secret"`
Domain string `json:"domain"`
TxtRecordName string `json:"txt_record_name"` // ← 第 28 行
SyncMode string `json:"sync_mode"`
RetryInterval int `json:"retry_interval"`
MaxRetries int `json:"max_retries"`
Enabled bool `json:"enabled"`
}
// 第 80-85 行:参数校验
if req.TxtRecordName == "" {
c.JSON(http.StatusBadRequest, gin.H{
"error": "请输入 TXT 记录名称",
})
return
}
验证点:
- ✅ 请求结构体包含字段
- ✅ JSON tag 正确
- ✅ 有必填校验
✅ 后端 Service - 有 TXT 字段
文件: internal/service/ddns.go
// DDNSConfig DDNS 配置(API 层使用)
type DDNSConfig struct {
Provider string `json:"provider"`
AccessKeyID string `json:"access_key_id"`
AccessKeySecret string `json:"access_key_secret"`
Domain string `json:"domain"`
TxtRecordName string `json:"txt_record_name"` // ← 第 42 行
SyncMode string `json:"sync_mode"`
RetryInterval int `json:"retry_interval"`
MaxRetries int `json:"max_retries"`
Enabled bool `json:"enabled"`
LastSyncAt *time.Time `json:"last_sync_at"`
PendingNetworks int `json:"pending_networks"`
Status string `json:"status"`
LastTestAt *time.Time `json:"last_test_at"`
LatencyMs int `json:"latency_ms"`
}
验证点:
- ✅ 配置结构体包含字段
- ✅ JSON tag 正确
✅ 数据库 Model - 有 TXT 字段
文件: internal/model/models.go
// DDNSConfig DDNS 配置模型
type DDNSConfig struct {
ID string `gorm:"primaryKey;type:varchar(36)" json:"id"`
Provider string `gorm:"type:varchar(32);not null" json:"provider"`
AccessKey string `gorm:"type:varchar(128);not null" json:"accessKey"`
SecretKey string `gorm:"type:varchar(128);not null" json:"-"`
Domain string `gorm:"type:varchar(255);not null" json:"domain"`
TXTRecordName string `gorm:"type:varchar(255)" json:"txtRecordName"` // ← 第 232 行
SyncMode string `gorm:"type:varchar(16);default:'auto'" json:"syncMode"`
RetryCount int `gorm:"default:10" json:"retryCount"`
RetryInterval int `gorm:"default:300" json:"retryInterval"`
Enabled bool `gorm:"default:true" json:"enabled"`
CreatedAt time.Time `gorm:"autoCreateTime" json:"createdAt"`
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updatedAt"`
}
验证点:
- ✅ 数据库字段存在
- ✅ GORM tag 正确
- ✅ JSON tag 正确
📊 全链路验证
| 层级 | 文件 | 字段名 | Tag | 状态 |
|---|---|---|---|---|
| 前端 UI | DDNSEdit.vue |
txt_record_name |
N/A | ✅ |
| 前端 API | ddns.js |
txt_record_name |
N/A | ✅ |
| 后端 Handler | ddns.go |
TxtRecordName |
json:"txt_record_name" |
✅ |
| 后端 Service | ddns.go |
TxtRecordName |
json:"txt_record_name" |
✅ |
| 数据库 Model | models.go |
TXTRecordName |
json:"txtRecordName" |
✅ |
⚠️ 可能的问题
问题 1: 浏览器缓存
症状: 前端页面看不到 TXT 字段
原因: 浏览器缓存了旧版本的 JS 文件
解决方案:
1. 按 Ctrl+Shift+Delete 清除缓存
2. 或强制刷新:Ctrl+F5
3. 或在无痕模式下访问
问题 2: 前端未重新编译
症状: 修改代码后仍然显示旧界面
原因: 前端代码修改后没有重新编译
解决方案:
cd web
npm run build
然后重启后端服务。
问题 3: JSON Tag 不一致(已排除)✅
检查结果:
- 前端:
txt_record_name✅ - 后端接收:
txt_record_name✅ - 后端返回:
txt_record_name✅ - 数据库:
txtRecordName(Go 命名) /txt_record_name(JSON) ✅
结论: JSON Tag 完全一致,无问题。
问题 4: 数据库迁移问题(待验证)
可能情况: 数据库表结构没有 txt_record_name 列
验证方法:
-- 查看 ddns_configs 表结构
PRAGMA table_info(ddns_configs);
-- 应该看到 txt_record_name 列
解决方案(如果确实缺失):
# 删除旧数据库(测试环境)
Remove-Item .\data\meshray.db -Force
# 重启服务,自动创建新表
.\meshray.exe
🎯 调试步骤
第一步:检查前端网络请求
- 打开浏览器开发者工具(F12)
- 切换到 Network 标签页
- 访问 DDNS 配置页面
- 找到
/api/v1/ddns/config请求 - 查看响应数据
期望响应:
{
"data": {
"provider": "aliyun",
"access_key_id": "",
"access_key_secret": "",
"domain": "",
"txt_record_name": "_meshray._mesh", // ← 应该有这个字段
"sync_mode": "auto",
"retry_interval": 5,
"max_retries": 10,
"enabled": true
}
}
如果响应中没有 txt_record_name:
- 可能是后端 Service 返回的数据有问题
- 检查
internal/service/ddns.go的GetConfig方法
第二步:检查前端表单渲染
- 在浏览器中打开开发者工具
- 使用元素选择器(Ctrl+Shift+C)
- 点击"TXT 记录名称"输入框
- 查看绑定的数据
期望看到:
<el-input
v-model="formData.txt_record_name"
placeholder="_meshray._mesh"
/>
如果找不到这个字段:
- 可能是 Vue 组件没有正确编译
- 需要重新执行
npm run build
第三步:检查后端日志
# 启动服务时查看详细日志
.\meshray.exe
查找类似日志:
获取 DDNS 配置成功
返回配置:{Provider:aliyun Domain:example.com TxtRecordName:_meshray._mesh ...}
💡 建议
最可能的原因
根据经验,90% 的情况是:
- 浏览器缓存 - 清缓存即可解决
- 前端未重新编译 - 执行
npm run build
快速验证
访问:http://localhost:9531/service/ddns/edit
然后在浏览器控制台执行:
// 检查 API 返回
fetch('/api/v1/ddns/config')
.then(r => r.json())
.then(d => {
console.log('完整数据:', d.data);
console.log('TXT 记录名称:', d.data.txt_record_name);
});
如果控制台显示有 txt_record_name 字段,说明后端正常,问题在前端显示层面。
📝 总结
✅ 已确认的事实
- 前端代码 - 有 TXT 字段(第 65-79 行)
- 前端 API - 有 TXT 字段(类型定义第 9 行)
- 后端 Handler - 有 TXT 字段(第 28 行,80-85 行校验)
- 后端 Service - 有 TXT 字段(第 42 行)
- 数据库 Model - 有 TXT 字段(第 232 行)
🔍 全链路完整
用户输入 → formData.txt_record_name
↓
前端 API → request({ txt_record_name: "..." })
↓
后端接收 → TxtRecordName string `json:"txt_record_name"`
↓
Service → DDNSConfig.TxtRecordName
↓
数据库 → TXTRecordName (GORM 自动映射)
🎯 下一步行动
请按以下顺序排查:
- 清除浏览器缓存(Ctrl+Shift+Delete)
- 强制刷新页面(Ctrl+F5)
- 检查网络请求(F12 → Network)
- 重新编译前端(如果需要)
cd web npm run build
DDNS TXT 记录字段排查报告 | v1.0