后端与接口
在 Go 的 API 边界做防御性加固(拷贝…
当需要在 Go 代码的 API 边界提升健壮性——防止调用方与被调方共享底层数据、避免漏掉资源清理、用错时间类型或非安全随机数时使用。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 49/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 85/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 60/100 ×0.15
适用场景
在 Go 的 API 边界做防御性加固(通用
解决思路
- 按优先级顺序检查 API 边界:1) 错误处理(返回 error 而非 panic,见 go-error-handling);2) 输入校验(复制调用方传入的 slice/map);3) 输出安全(返回前复制 slice/map);4) 资源清理(Close/Unlock/Cancel 用 defer);5) 接口检查(编译期断言交给 go-interfaces);6) 时间正确性(用 time.Time/time.Duration,不用 int/float);7) 枚举安全(iota 从 1 开始,让零值无效);8) 加密安全(密钥用 crypto/rand,绝不用 math/rand)。
- 接收外部传入的 slice 时立即复制到自己的字段:d.trips = make([]Trip, len(trips)); copy(d.trips, trips),因为 slice/map 内部是指向底层数据的指针,不复制会被外部意外修改。
- 返回内部 map/slice 给调用方前先复制:result := make(map[string]int, len(s.counters)); for k, v := range s.counters { result[k] = v }。
- 用 defer 清理文件、锁等资源:p.Lock() 后紧跟 defer p.Unlock();os.Open 之后立即写 defer f.Close(),避免多条 return 路径漏掉清理。
- 注意 defer 的语义细节:defer 的开销可忽略,不必为性能规避;defer 函数实参在 defer 语句执行时求值(而非函数真正运行时);多个 defer 按 LIFO 顺序执行。
- 为所有会被 marshal/unmarshal 的结构体加显式字段标签(如 json:"name" yaml:"name");把 tag 当作序列化契约与公开 API 的一部分,重命名字段时必须同步改 tag,否则会静默破坏线上兼容性。
- 枚举从非零值开始以区分「未初始化」与合法值:const ( Add Operation = iota + 1; Subtract; Multiply );例外是零值本身就是合理默认值时(如 LogToStdout = iota)。
- 时间类型统一使用 time.Time 与 time.Duration,不要用裸 int/float 表示时间。
- 不要使用可变包级全局变量,改为依赖注入,使代码可在测试中替换而无需全局 save/restore,例如 type signer struct { now func() time.Time },构造函数里注入 time.Now。
- 生成密钥等安全敏感随机值必须用 crypto/rand,禁止用 math/rand 或 math/rand/v2(时间种子可预测,属安全问题);文本输出直接用 crypto/rand.Text(需 Go 1.24+),或对随机字节做 encoding/hex、encoding/base64 编码。
- panic 只用于真正不可恢复的情况,库函数应避免 panic;绝不让 panic 跨包边界传播,必须转换成 error 返回。
- 只有库确实无法完成初始化时才允许在 init() 中 panic。
- 用 defer + recover 在服务器 goroutine handler 中隔离 panic:defer func(){ if err := recover(); err != nil { log.Println("work failed:", err) } }()。
- Must 系列函数只在程序初始化阶段使用(失败即程序无法运行),例如 var validID = regexp.MustCompile(`^[a-z][a-z0-9-]{0,62}$`)、var tmpl = template.Must(template.ParseFiles("index.html"))。
- 按需查阅细分参考文档:references/BOUNDARY-COPYING.md(跨 API 边界复制 slice/map)、references/GLOBAL-STATE.md(引入或移除包级全局变量)、references/MUST-FUNCTIONS.md(判断 panic-on-error 辅助函数是否可接受)、references/PANIC-RECOVER.md(评估 panic/recover/崩溃隔离)、references/TIME-ENUMS-TAGS.md(时间类型、枚举零值、结构体 tag)。
- 跨技能路由:错误与 panic 的选择及边界处包装 error 见 go-error-handling;用 mutex/atomic/channel 保护共享状态见 go-concurrency;编译期接口满足性断言见 go-interfaces;slice/map 内部结构与指针别名见 go-data-structures。
适用边界 · 注意事项
- 不覆盖错误处理策略(何时返回 error、如何包装),那属于 go-error-handling 技能。
- 不负责编译期接口断言的适用时机与确切写法,那由 go-interfaces 技能决定;本技能只用于发现 API 边界的健壮性风险。
- crypto/rand.Text 需要 Go 1.24+;枚举零值本身即为合法默认值的场景不适用「iota 从 1 开始」。