8ad4c3576d
- Fixed verifyAssignment being too strict for new clients - Fixed parseRequestedIP string conversion bug - Fixed response sent to 0.0.0.0 instead of broadcast address - Added SO_BROADCAST support for UDP socket - Fixed session persistence after page refresh (localStorage) - Added in-memory session store for auth middleware - Added config reloader so DHCP server picks up web UI changes dynamically
211 lines
5.2 KiB
Markdown
211 lines
5.2 KiB
Markdown
# 🔧 修复总结 - JSON 响应问题
|
||
|
||
## 🐛 问题描述
|
||
|
||
用户报告保存配置时出现错误:
|
||
```
|
||
保存失败:Unexpected non-whitespace character after JSON at position 4 (line 1 column 5)
|
||
```
|
||
|
||
**根本原因**:服务器返回了非 JSON 格式的响应,前端无法解析。
|
||
|
||
---
|
||
|
||
## ✅ 已修复内容
|
||
|
||
### 1. 后端修复
|
||
|
||
#### 自定义错误恢复中间件
|
||
```go
|
||
// 替换默认的 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()
|
||
}))
|
||
```
|
||
|
||
#### 部分更新支持
|
||
```go
|
||
// 改为接收 map[string]interface{} 支持部分字段更新
|
||
func (cm *ConfigManager) UpdateDHCPConfig(updates map[string]interface{}) error
|
||
func (cm *ConfigManager) UpdateDNSConfig(updates map[string]interface{}) error
|
||
```
|
||
|
||
#### 配置管理器注入
|
||
```go
|
||
// 通过中间件注入 ConfigManager 到上下文
|
||
s.router.Use(func(c *gin.Context) {
|
||
c.Set("configManager", s.configManager)
|
||
c.Next()
|
||
})
|
||
```
|
||
|
||
#### 健康检查端点
|
||
```go
|
||
s.router.GET("/api/health", func(c *gin.Context) {
|
||
c.JSON(http.StatusOK, gin.H{"status": "ok", "message": "Server is running"})
|
||
})
|
||
```
|
||
|
||
### 2. 前端修复
|
||
|
||
#### 响应类型验证
|
||
```javascript
|
||
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;
|
||
}
|
||
```
|
||
|
||
#### 错误处理增强
|
||
```javascript
|
||
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 配置字段
|
||
```go
|
||
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 配置字段
|
||
```go
|
||
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:运行测试脚本
|
||
```bash
|
||
cd /vol1/@apphome/trim.openclaw/data/workspace/dhcp-dns-manager
|
||
./test-api.sh
|
||
```
|
||
|
||
### 方法 2:手动测试
|
||
```bash
|
||
# 健康检查
|
||
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. 查看响应内容
|
||
|
||
---
|
||
|
||
## 🚀 重新部署
|
||
|
||
```bash
|
||
cd /vol1/@apphome/trim.openclaw/data/workspace/dhcp-dns-manager
|
||
sudo ./install.sh
|
||
```
|
||
|
||
---
|
||
|
||
## ✅ 验证清单
|
||
|
||
- [x] 所有 API 响应都是 JSON 格式
|
||
- [x] 错误处理返回 JSON 格式
|
||
- [x] 支持部分字段更新
|
||
- [x] 配置管理器正确初始化
|
||
- [x] 前端正确验证响应类型
|
||
- [x] 健康检查端点可用
|
||
- [x] 完整配置字段支持
|
||
|
||
---
|
||
|
||
## 📞 如果问题仍然存在
|
||
|
||
1. **查看服务器日志**:
|
||
```bash
|
||
sudo journalctl -u dhcp-dns-manager -f
|
||
```
|
||
|
||
2. **查看浏览器控制台**:
|
||
- 打开 F12 开发者工具
|
||
- 查看 Console 和 Network 标签
|
||
|
||
3. **运行测试脚本**:
|
||
```bash
|
||
./test-api.sh
|
||
```
|
||
|
||
4. **检查配置文件**:
|
||
```bash
|
||
cat /opt/dhcp-dns-manager/configs/config.json | python3 -m json.tool
|
||
```
|
||
|
||
---
|
||
|
||
**修复日期**: 2026-04-23
|
||
**版本**: v0.2.1
|
||
**状态**: ✅ 已修复
|