实现七月迭代公共技术基础
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 9m20s

This commit is contained in:
2026-07-23 17:52:48 +09:00
parent f7c42252c0
commit 17782d5f8e
76 changed files with 5246 additions and 158 deletions

View File

@@ -0,0 +1,124 @@
// Package idempotency 提供创建类命令的幂等身份与请求指纹公共契约。
package idempotency
import (
"crypto/sha256"
"encoding/hex"
"reflect"
"strings"
"github.com/bytedance/sonic"
)
const (
// FingerprintAlgorithmV1 是请求指纹算法的首个稳定版本。
FingerprintAlgorithmV1 = "sha256-canonical-json-v1"
)
// Scope 表示请求 ID 的幂等作用域。
type Scope struct {
Subject string `json:"subject"`
Operation string `json:"operation"`
}
// FingerprintValue 表示带算法版本的请求指纹。
type FingerprintValue struct {
Algorithm string `json:"algorithm"`
Value string `json:"value"`
}
// Record 表示业务模块自行持久化的幂等事实最小投影。
type Record struct {
Scope Scope `json:"scope"`
RequestID string `json:"request_id"`
Fingerprint FingerprintValue `json:"fingerprint"`
}
// ReplayKind 表示已有事实与本次命令的关系。
type ReplayKind string
const (
// ReplaySame 表示相同命令重放,应返回原业务结果。
ReplaySame ReplayKind = "same"
// ReplayConflict 表示同作用域、同请求 ID 携带了不同业务内容。
ReplayConflict ReplayKind = "conflict"
// ReplayUnrelated 表示不是同一幂等作用域内的命令。
ReplayUnrelated ReplayKind = "unrelated"
)
var volatileFieldNames = map[string]struct{}{
"authorization": {},
"cookie": {},
"nonce": {},
"sign": {},
"signature": {},
"timestamp": {},
"token": {},
}
// Fingerprint 对影响业务结果的规范化字段计算稳定指纹。
//
// 调用方仍应优先传入专用命令 DTO本函数会递归排除约定的易变传输字段
// 并去除字符串首尾空白,避免签名、令牌或对象字段顺序污染业务身份。
func Fingerprint(command any) (FingerprintValue, error) {
raw, err := sonic.ConfigStd.Marshal(command)
if err != nil {
return FingerprintValue{}, err
}
var value any
if err := sonic.Unmarshal(raw, &value); err != nil {
return FingerprintValue{}, err
}
normalized := normalize(value)
canonical, err := sonic.ConfigStd.Marshal(normalized)
if err != nil {
return FingerprintValue{}, err
}
sum := sha256.Sum256(canonical)
return FingerprintValue{
Algorithm: FingerprintAlgorithmV1,
Value: hex.EncodeToString(sum[:]),
}, nil
}
// ValidateScope 校验幂等作用域和稳定请求 ID 是否完整。
func ValidateScope(scope Scope, requestID string) bool {
return strings.TrimSpace(scope.Subject) != "" &&
strings.TrimSpace(scope.Operation) != "" &&
strings.TrimSpace(requestID) != ""
}
// Classify 比较已有幂等事实与本次命令。
func Classify(existing Record, scope Scope, requestID string, fingerprint FingerprintValue) ReplayKind {
if existing.Scope != scope || existing.RequestID != requestID {
return ReplayUnrelated
}
if reflect.DeepEqual(existing.Fingerprint, fingerprint) {
return ReplaySame
}
return ReplayConflict
}
func normalize(value any) any {
switch typed := value.(type) {
case map[string]any:
result := make(map[string]any, len(typed))
for key, item := range typed {
if _, volatile := volatileFieldNames[strings.ToLower(strings.TrimSpace(key))]; volatile {
continue
}
result[key] = normalize(item)
}
return result
case []any:
result := make([]any, len(typed))
for index, item := range typed {
result[index] = normalize(item)
}
return result
case string:
return strings.TrimSpace(typed)
default:
return value
}
}