Files
xlgo-core/config/validate.go
T
杭州明婳科技 0c9f256dfc feat(v1.1.0): HA & Manager 化
对应体检报告 #10-#24,一次性完成 v1.1.0 全部 13 项:

- #10 storage/cache/redis/jwt/logger 五组件 Manager 化(XxxManager + DefaultXxx + SetDefaultXxxManager,包级 facade 保留兼容)
- #11 删除 wire 包 + 清理 StartServerWithPort/GracefulShutdown 双轨
- #12 Lifecycle Hooks(OnInit/OnStart/OnReady/OnStop)
- #13 Server 参数配置化(timeout/TLS/unix_socket/response_mode)
- #14 JWTConfig.Expire 改 time.Duration + 删 AppConfig.TokenExpire
- #15 response Mode 开关(ModeBusiness/ModeREST)
- #16 Config.Validate 启动期校验
- #17 livez/readyz 探针路由
- #18 Prometheus metrics 中间件 + /metrics
- #19 请求级 Timeout 中间件
- #21 主库探活 + replica 健康剔除
- #22 App.Go + in-flight goroutine 管理
- #24 RequestID 默认装入 + #23 核对

Breaking:删 wire、删 TokenExpire、JWTConfig.Expire 类型变更、删双轨函数。
详见 CHANGELOG 升级说明。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-23 10:41:05 +08:00

70 lines
2.4 KiB
Go

package config
import (
"fmt"
"strings"
"time"
)
// Validate 校验配置完整性与取值合法性(#16)。
// 在 Manager.Load 解析后自动调用,把"运行时第一次请求才暴露"的配置错误
// 提前到进程启动期。返回的 error 描述具体字段,便于定位。
func (c *Config) Validate() error {
if c == nil {
return fmt.Errorf("配置为空")
}
var problems []string
// Server
if c.Server.Port < 0 || c.Server.Port > 65535 {
problems = append(problems, fmt.Sprintf("server.port 超出范围(0-65535): %d", c.Server.Port))
}
if c.Server.TLS.Enabled {
if strings.TrimSpace(c.Server.TLS.CertFile) == "" || strings.TrimSpace(c.Server.TLS.KeyFile) == "" {
problems = append(problems, "server.tls 启用后必须同时配置 cert_file 与 key_file")
}
}
if !validDuration(c.Server.ReadTimeout) || !validDuration(c.Server.WriteTimeout) ||
!validDuration(c.Server.IdleTimeout) || !validDuration(c.Server.ShutdownTimeout) {
problems = append(problems, "server 的 timeout 配置不能为负值")
}
// JWT:仅当配置了 secret 时校验(未启用 jwt 的项目可留空)
if c.JWT.Secret != "" {
if len(c.JWT.Secret) < 32 {
problems = append(problems, fmt.Sprintf("jwt.secret 长度不足 32 字节(当前 %d),HMAC 密钥过短不安全", len(c.JWT.Secret)))
}
if c.JWT.Expire < 0 || c.JWT.RefreshExpire < 0 {
problems = append(problems, "jwt.expire / jwt.refresh_expire 不能为负值")
}
}
// Database:仅当配置了 driver 时校验(未启用 mysql 的项目可留空)
if strings.TrimSpace(c.Database.Driver) != "" {
if c.Database.Host == "" {
problems = append(problems, "database.host 启用数据库后必填")
}
if c.Database.Name == "" {
problems = append(problems, "database.name 启用数据库后必填")
}
if c.Database.Port <= 0 || c.Database.Port > 65535 {
problems = append(problems, fmt.Sprintf("database.port 超出范围(1-65535): %d", c.Database.Port))
}
}
// Redis:仅当配置了 host 时校验
if strings.TrimSpace(c.Redis.Host) != "" {
if c.Redis.Port <= 0 || c.Redis.Port > 65535 {
problems = append(problems, fmt.Sprintf("redis.port 超出范围(1-65535): %d", c.Redis.Port))
}
}
if len(problems) > 0 {
return fmt.Errorf("配置校验失败: %s", strings.Join(problems, "; "))
}
return nil
}
// validDuration 校验 Duration 非负(0 表示未配置/用默认,合法)。
func validDuration(d time.Duration) bool { return d >= 0 }