后端: - 新增全局设备管理 API(DeviceHandler.GetAllDevices) - 新增登录日志导出功能(LogHandler.ExportLoginLogs, CSV/XLSX) - 新增设置服务(SettingsService)和设置页面 API - 设备管理支持多条件筛选(状态/信任状态/关键词) - 登录日志支持流式导出防 OOM - 操作日志支持按方法/时间范围搜索 - 主题配置服务(ThemeService) - 增强监控健康检查(Prometheus metrics + SLO) - 移除旧 ratelimit.go(已迁移至 robustness) - 修复 SocialAccount NULL 扫描问题 - 新增 API 契约测试、Handler 测试、Settings 测试 前端: - 新增管理员设备管理页面(DevicesPage) - 新增管理员登录日志导出功能 - 新增系统设置页面(SettingsPage) - 设备管理支持筛选和分页 - 增强 HTTP 响应类型 测试: - 业务逻辑测试 68 个(含并发 CONC_001~003) - 规模测试 16 个(P99 百分位统计) - E2E 测试、集成测试、契约测试 - 性能基准测试、鲁棒性测试 全面测试通过(38 个测试包)
57 lines
1.3 KiB
Go
57 lines
1.3 KiB
Go
package middleware
|
||
|
||
import (
|
||
"crypto/rand"
|
||
"encoding/hex"
|
||
"fmt"
|
||
"time"
|
||
|
||
"github.com/gin-gonic/gin"
|
||
)
|
||
|
||
const (
|
||
// TraceIDHeader 追踪 ID 的 HTTP 响应头名称
|
||
TraceIDHeader = "X-Trace-ID"
|
||
// TraceIDKey gin.Context 中的 key
|
||
TraceIDKey = "trace_id"
|
||
)
|
||
|
||
// TraceID 中间件:为每个请求生成唯一追踪 ID
|
||
// 追踪 ID 写入 gin.Context 和响应头,供日志和下游服务关联
|
||
func TraceID() gin.HandlerFunc {
|
||
return func(c *gin.Context) {
|
||
// 优先复用上游传入的 Trace ID(如 API 网关、前端)
|
||
traceID := c.GetHeader(TraceIDHeader)
|
||
if traceID == "" {
|
||
traceID = generateTraceID()
|
||
}
|
||
|
||
c.Set(TraceIDKey, traceID)
|
||
c.Header(TraceIDHeader, traceID)
|
||
|
||
c.Next()
|
||
}
|
||
}
|
||
|
||
// generateTraceID 生成 16 字节随机 hex 字符串,格式:时间前缀+随机后缀
|
||
// 例:20260405-a1b2c3d4e5f60718
|
||
func generateTraceID() string {
|
||
b := make([]byte, 8)
|
||
_, err := rand.Read(b)
|
||
if err != nil {
|
||
// 降级:使用时间戳
|
||
return fmt.Sprintf("%d", time.Now().UnixNano())
|
||
}
|
||
return fmt.Sprintf("%s-%s", time.Now().Format("20060102"), hex.EncodeToString(b))
|
||
}
|
||
|
||
// GetTraceID 从 gin.Context 获取 trace ID(供 handler 使用)
|
||
func GetTraceID(c *gin.Context) string {
|
||
if v, exists := c.Get(TraceIDKey); exists {
|
||
if id, ok := v.(string); ok {
|
||
return id
|
||
}
|
||
}
|
||
return ""
|
||
}
|