FIX_SUMMARY.md 5.2 KB

🔧 修复总结 - JSON 响应问题

🐛 问题描述

用户报告保存配置时出现错误:

保存失败:Unexpected non-whitespace character after JSON at position 4 (line 1 column 5)

根本原因:服务器返回了非 JSON 格式的响应,前端无法解析。


✅ 已修复内容

1. 后端修复

自定义错误恢复中间件

// 替换默认的 gin.Recovery() 为自定义 JSON 错误恢复
s.router.Use(gin.CustomRecovery(func(c *gin.Context, err any) {
    c.JSON(http.StatusInternalServerError, gin.H{
        "error": fmt.Sprintf("Internal server error: %v", err),
    })
    c.Abort()
}))

部分更新支持

// 改为接收 map[string]interface{} 支持部分字段更新
func (cm *ConfigManager) UpdateDHCPConfig(updates map[string]interface{}) error
func (cm *ConfigManager) UpdateDNSConfig(updates map[string]interface{}) error

配置管理器注入

// 通过中间件注入 ConfigManager 到上下文
s.router.Use(func(c *gin.Context) {
    c.Set("configManager", s.configManager)
    c.Next()
})

健康检查端点

s.router.GET("/api/health", func(c *gin.Context) {
    c.JSON(http.StatusOK, gin.H{"status": "ok", "message": "Server is running"})
})

2. 前端修复

响应类型验证

const contentType = response.headers.get('content-type');
if (!contentType || !contentType.includes('application/json')) {
    const text = await response.text();
    console.error('Non-JSON response:', text);
    alert('服务器返回了非 JSON 格式响应,请查看控制台');
    return;
}

错误处理增强

try {
    const response = await fetch('/api/dhcp/config', {...});
    const data = await response.json();
    
    if (response.ok) {
        alert('配置已保存');
    } else {
        alert('保存失败:' + (data.error || '未知错误'));
    }
} catch (error) {
    console.error('Save error:', error);
    alert('保存失败:' + error.message);
}

3. 配置结构完善

DHCP 配置字段

type DHCPConfig struct {
    Enabled          bool     `json:"enabled"`
    Interface        string   `json:"interface"`
    Network          string   `json:"network"`
    Netmask          string   `json:"netmask"`
    Gateway          string   `json:"gateway"`
    DNSServers       []string `json:"dns_servers"`
    NTPServers       []string `json:"ntp_servers"`
    BroadcastAddress string   `json:"broadcast_address"`
    LeaseTime        int      `json:"lease_time"`
    IPPoolStart      string   `json:"ip_pool_start"`
    IPPoolEnd        string   `json:"ip_pool_end"`
    DomainName       string   `json:"domain_name"`
    ExcludedIPs      []string `json:"excluded_ips"`
}

DNS 配置字段

type DNSConfig struct {
    Enabled          bool     `json:"enabled"`
    ListenAddr       string   `json:"listen_addr"`
    ListenPort       int      `json:"listen_port"`
    Upstream         []string `json:"upstream"`
    CacheSize        int      `json:"cache_size"`
    CacheTTL         int      `json:"cache_ttl"`
    Recursion        bool     `json:"recursion"`
    AllowQuery       []string `json:"allow_query"`
    DNSSECValidation bool     `json:"dnssec_validation"`
}

📁 修改的文件

文件 修改内容
internal/web/server.go 添加自定义恢复中间件、ConfigManager 注入、健康检查端点
internal/web/config_handler.go 改为部分更新支持、完善错误处理
internal/config/config.go 添加完整配置字段
cmd/main.go 添加 ConfigManager 初始化
web/static/js/app.js 增强错误处理、响应类型验证
configs/config.json 更新为完整配置示例

🧪 测试方法

方法 1:运行测试脚本

cd /vol1/@apphome/trim.openclaw/data/workspace/dhcp-dns-manager
./test-api.sh

方法 2:手动测试

# 健康检查
curl http://localhost:8080/api/health

# 获取 DHCP 配置
curl -H "X-Session-ID: test" http://localhost:8080/api/dhcp/config

# 更新 DHCP 配置
curl -X PUT -H "X-Session-ID: test" \
  -H "Content-Type: application/json" \
  -d '{"network":"192.168.1.0"}' \
  http://localhost:8080/api/dhcp/config

方法 3:浏览器测试

  1. 打开浏览器开发者工具(F12)
  2. 进入 Network 标签
  3. 尝试保存配置
  4. 查看响应内容

🚀 重新部署

cd /vol1/@apphome/trim.openclaw/data/workspace/dhcp-dns-manager
sudo ./install.sh

✅ 验证清单

  • 所有 API 响应都是 JSON 格式
  • 错误处理返回 JSON 格式
  • 支持部分字段更新
  • 配置管理器正确初始化
  • 前端正确验证响应类型
  • 健康检查端点可用
  • 完整配置字段支持

📞 如果问题仍然存在

  1. 查看服务器日志

    sudo journalctl -u dhcp-dns-manager -f
    
  2. 查看浏览器控制台

    • 打开 F12 开发者工具
    • 查看 Console 和 Network 标签
  3. 运行测试脚本

    ./test-api.sh
    
  4. 检查配置文件

    cat /opt/dhcp-dns-manager/configs/config.json | python3 -m json.tool
    

修复日期: 2026-04-23
版本: v0.2.1
状态: ✅ 已修复