Files
Meshray-Manager/docs/DDNS_TXT 字段排查报告.md
2026-06-30 15:14:37 +08:00

9.1 KiB
Raw Permalink Blame History

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

🎯 调试步骤

第一步:检查前端网络请求

  1. 打开浏览器开发者工具(F12
  2. 切换到 Network 标签页
  3. 访问 DDNS 配置页面
  4. 找到 /api/v1/ddns/config 请求
  5. 查看响应数据

期望响应:

{
  "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.goGetConfig 方法

第二步:检查前端表单渲染

  1. 在浏览器中打开开发者工具
  2. 使用元素选择器(Ctrl+Shift+C
  3. 点击"TXT 记录名称"输入框
  4. 查看绑定的数据

期望看到:

<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% 的情况是:

  1. 浏览器缓存 - 清缓存即可解决
  2. 前端未重新编译 - 执行 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 字段,说明后端正常,问题在前端显示层面。


📝 总结

已确认的事实

  1. 前端代码 - 有 TXT 字段(第 65-79 行)
  2. 前端 API - 有 TXT 字段(类型定义第 9 行)
  3. 后端 Handler - 有 TXT 字段(第 28 行,80-85 行校验)
  4. 后端 Service - 有 TXT 字段(第 42 行)
  5. 数据库 Model - 有 TXT 字段(第 232 行)

🔍 全链路完整

用户输入 → formData.txt_record_name
   ↓
前端 API → request({ txt_record_name: "..." })
   ↓
后端接收 → TxtRecordName string `json:"txt_record_name"`
   ↓
Service → DDNSConfig.TxtRecordName
   ↓
数据库 → TXTRecordName (GORM 自动映射)

🎯 下一步行动

请按以下顺序排查:

  1. 清除浏览器缓存Ctrl+Shift+Delete
  2. 强制刷新页面Ctrl+F5
  3. 检查网络请求F12 → Network
  4. 重新编译前端(如果需要)
    cd web
    npm run build
    

DDNS TXT 记录字段排查报告 | v1.0