feat(config): 增强配置解析的语法校验与错误处理
- 重构 ParseConfigToKVMap 使其在解析失败时返回 error 而非静默忽略 - 新增 ValidateConfig 方法,在保存和更新配置前校验语法正确性 - 将 XML 解析器从简单字符串匹配改为标准库 xml.NewDecoder,支持嵌套标签和实体转义 - 在配置保存和更新接口中集成语法校验,校验失败返回 400 错误 - API 拉取配置时解析失败的条目记录日志并跳过,避免整体请求中断 - 新增 config_parse_test.go 覆盖各配置类型的正常与异常场景
This commit is contained in:
@@ -231,6 +231,11 @@ func (h *ConfigHandler) Add(c *gin.Context) {
|
||||
}
|
||||
}
|
||||
|
||||
if err := h.parseService.ValidateConfig(&config); err != nil {
|
||||
c.JSON(http.StatusOK, model.WrapperResponse{Code: 400, Msg: err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
if _, err := dao.Engine.Insert(&config); err != nil {
|
||||
c.JSON(http.StatusOK, model.WrapperResponse{Code: 500, Msg: "保存失败"})
|
||||
return
|
||||
@@ -264,6 +269,15 @@ func (h *ConfigHandler) Update(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
// 校验新内容语法,避免保存后客户端解析失败
|
||||
newConfig := config
|
||||
newConfig.Contents = req.Contents
|
||||
newConfig.Version = req.Version
|
||||
if err := h.parseService.ValidateConfig(&newConfig); err != nil {
|
||||
c.JSON(http.StatusOK, model.WrapperResponse{Code: 400, Msg: err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
// save history
|
||||
h.saveHistory(&config, userInfo.Name, "update")
|
||||
|
||||
|
||||
@@ -108,8 +108,12 @@ func (h *ConfigApiHandler) FetchAllConfigs(c *gin.Context) {
|
||||
dao.Engine.Where("env = ? AND version = ? AND enabled = 1 AND group_id = ? AND (app_id is null OR app_id = 0)",
|
||||
req.Env, version, *app.GroupId).Find(&globalConfigs)
|
||||
for _, cfg := range globalConfigs {
|
||||
kvMap, err := h.parseService.ParseConfigToKVMap(&cfg)
|
||||
if err != nil {
|
||||
logger.SugaredLogger.Errorf("[FetchAllConfigs] parse config %d (%s) error: %v", cfg.Id, cfg.Name, err)
|
||||
continue
|
||||
}
|
||||
configIds = append(configIds, cfg.Id)
|
||||
kvMap := h.parseService.ParseConfigToKVMap(&cfg)
|
||||
for k, v := range kvMap {
|
||||
result[k] = v
|
||||
}
|
||||
@@ -121,8 +125,12 @@ func (h *ConfigApiHandler) FetchAllConfigs(c *gin.Context) {
|
||||
dao.Engine.Where("env = ? AND version = ? AND enabled = 1 AND app_id = ?",
|
||||
req.Env, version, app.Id).Find(&appConfigs)
|
||||
for _, cfg := range appConfigs {
|
||||
kvMap, err := h.parseService.ParseConfigToKVMap(&cfg)
|
||||
if err != nil {
|
||||
logger.SugaredLogger.Errorf("[FetchAllConfigs] parse config %d (%s) error: %v", cfg.Id, cfg.Name, err)
|
||||
continue
|
||||
}
|
||||
configIds = append(configIds, cfg.Id)
|
||||
kvMap := h.parseService.ParseConfigToKVMap(&cfg)
|
||||
for k, v := range kvMap {
|
||||
result[k] = v
|
||||
}
|
||||
@@ -197,7 +205,11 @@ func (h *ConfigApiHandler) FetchChangedConfigs(c *gin.Context) {
|
||||
dao.Engine.Where("env = ? AND version = ? AND enabled = 0 AND group_id = ? AND (app_id is null OR app_id = 0) AND updated_at > ? AND updated_at <= ?",
|
||||
req.Env, version, *app.GroupId, lastUpdateTime, upperBound).Find(&deletedGlobalConfigs)
|
||||
for _, cfg := range deletedGlobalConfigs {
|
||||
kvMap := h.parseService.ParseConfigToKVMap(&cfg)
|
||||
kvMap, err := h.parseService.ParseConfigToKVMap(&cfg)
|
||||
if err != nil {
|
||||
logger.SugaredLogger.Errorf("[FetchChangedConfigs] parse deleted config %d (%s) error: %v", cfg.Id, cfg.Name, err)
|
||||
continue
|
||||
}
|
||||
for k := range kvMap {
|
||||
deletedKeys = append(deletedKeys, k)
|
||||
}
|
||||
@@ -207,7 +219,11 @@ func (h *ConfigApiHandler) FetchChangedConfigs(c *gin.Context) {
|
||||
dao.Engine.Where("env = ? AND version = ? AND enabled = 0 AND app_id = ? AND updated_at > ? AND updated_at <= ?",
|
||||
req.Env, version, app.Id, lastUpdateTime, upperBound).Find(&deletedAppConfigs)
|
||||
for _, cfg := range deletedAppConfigs {
|
||||
kvMap := h.parseService.ParseConfigToKVMap(&cfg)
|
||||
kvMap, err := h.parseService.ParseConfigToKVMap(&cfg)
|
||||
if err != nil {
|
||||
logger.SugaredLogger.Errorf("[FetchChangedConfigs] parse deleted config %d (%s) error: %v", cfg.Id, cfg.Name, err)
|
||||
continue
|
||||
}
|
||||
for k := range kvMap {
|
||||
deletedKeys = append(deletedKeys, k)
|
||||
}
|
||||
@@ -222,8 +238,9 @@ func (h *ConfigApiHandler) FetchChangedConfigs(c *gin.Context) {
|
||||
dao.Engine.Where("env = ? AND version = ? AND enabled = 1 AND group_id = ? AND (app_id is null OR app_id = 0) AND updated_at > ? AND updated_at <= ?",
|
||||
req.Env, version, *app.GroupId, lastUpdateTime, upperBound).Find(&globalConfigs)
|
||||
for _, cfg := range globalConfigs {
|
||||
configIds = append(configIds, cfg.Id)
|
||||
h.addChangedConfigs(result, &cfg, req.FetchAll)
|
||||
if h.addChangedConfigs(result, &cfg, req.FetchAll) {
|
||||
configIds = append(configIds, cfg.Id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -232,8 +249,9 @@ func (h *ConfigApiHandler) FetchChangedConfigs(c *gin.Context) {
|
||||
dao.Engine.Where("env = ? AND version = ? AND enabled = 1 AND app_id = ? AND updated_at > ? AND updated_at <= ?",
|
||||
req.Env, version, app.Id, lastUpdateTime, upperBound).Find(&appConfigs1)
|
||||
for _, cfg := range appConfigs1 {
|
||||
configIds = append(configIds, cfg.Id)
|
||||
h.addChangedConfigs(result, &cfg, req.FetchAll)
|
||||
if h.addChangedConfigs(result, &cfg, req.FetchAll) {
|
||||
configIds = append(configIds, cfg.Id)
|
||||
}
|
||||
}
|
||||
|
||||
result["latest.fetch.timestamp"] = strconv.FormatInt(upperBound.UnixMilli(), 10)
|
||||
@@ -266,11 +284,16 @@ func (h *ConfigApiHandler) FetchChangedConfigs(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, model.WrapperResponse{Code: 0, Data: result})
|
||||
}
|
||||
|
||||
func (h *ConfigApiHandler) addChangedConfigs(result map[string]string, config *model.AppConfig, fetchAll bool) {
|
||||
kvMap := h.parseService.ParseConfigToKVMap(config)
|
||||
func (h *ConfigApiHandler) addChangedConfigs(result map[string]string, config *model.AppConfig, fetchAll bool) bool {
|
||||
kvMap, err := h.parseService.ParseConfigToKVMap(config)
|
||||
if err != nil {
|
||||
logger.SugaredLogger.Errorf("[FetchChangedConfigs] parse config %d (%s) error: %v", config.Id, config.Name, err)
|
||||
return false
|
||||
}
|
||||
for k, v := range kvMap {
|
||||
result[k] = fmt.Sprintf("%v", v)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (h *ConfigApiHandler) recordClientInstances(ip string, configIds []int, appName, env, fetchType string) {
|
||||
|
||||
Reference in New Issue
Block a user