Files
junhong_cmp_fiber/pkg/errors/context.go
huang 6f1350b527
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 4m31s
修复日志中间件的 UserID 类型转换 panic 问题
问题描述:
- 认证中间件存储的 UserID 是 uint 类型
- 日志中间件和错误上下文错误地将其断言为 string 类型
- 导致所有认证请求在记录访问日志时发生 panic

修复内容:
1. pkg/logger/middleware.go
   - 修改 UserID 变量类型从 string 为 uint
   - 使用安全的类型断言 (uid.(uint))
   - 使用 zap.Uint 记录日志

2. pkg/errors/context.go
   - 修改 UserID 类型断言从 string 为 uint
   - 使用 strconv.FormatUint 转换为 string 用于错误上下文

影响范围:
- 修复所有需要认证的接口的 panic 错误
- 包括 /api/admin/shops, /api/admin/me, /api/admin/permissions 等
2026-01-21 12:17:19 +08:00

93 lines
2.3 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package errors
import (
"strconv"
"github.com/gofiber/fiber/v2"
"go.uber.org/zap"
"github.com/break/junhong_cmp_fiber/pkg/constants"
)
// ErrorContext 错误发生时的请求上下文(用于日志记录)
type ErrorContext struct {
RequestID string // 请求 ID唯一标识
Method string // HTTP 方法
Path string // 请求路径
Query string // Query 参数
Body string // 请求 Body限制 50KB
IP string // 客户端 IP
UserAgent string // User-Agent
UserID string // 用户 ID如果已认证
}
const (
// MaxBodyLogSize 请求 Body 日志记录最大字节数50KB
MaxBodyLogSize = 50 * 1024
)
// FromFiberContext 从 Fiber Context 提取错误上下文
func FromFiberContext(c *fiber.Ctx) *ErrorContext {
ctx := &ErrorContext{
Method: c.Method(),
Path: c.Path(),
Query: c.Request().URI().QueryArgs().String(),
IP: c.IP(),
UserAgent: c.Get("User-Agent"),
}
// 提取 Request ID
if rid := c.Locals(constants.ContextKeyRequestID); rid != nil {
ctx.RequestID = rid.(string)
}
if ctx.RequestID == "" {
ctx.RequestID = c.Get("X-Request-ID")
}
// 提取 User ID如果已认证
if uid := c.Locals(constants.ContextKeyUserID); uid != nil {
if userID, ok := uid.(uint); ok {
ctx.UserID = strconv.FormatUint(uint64(userID), 10)
}
}
// 提取请求 Body限制 50KB
bodyBytes := c.Body()
if len(bodyBytes) > 0 {
if len(bodyBytes) > MaxBodyLogSize {
// 超过限制时截断并添加提示
ctx.Body = string(bodyBytes[:MaxBodyLogSize]) + " ... (truncated)"
} else {
ctx.Body = string(bodyBytes)
}
}
return ctx
}
// ToLogFields 转换为 Zap 日志字段
func (ec *ErrorContext) ToLogFields() []zap.Field {
fields := []zap.Field{
zap.String("request_id", ec.RequestID),
zap.String("method", ec.Method),
zap.String("path", ec.Path),
zap.String("ip", ec.IP),
}
// 可选字段(非空时添加)
if ec.Query != "" {
fields = append(fields, zap.String("query", ec.Query))
}
if ec.Body != "" {
fields = append(fields, zap.String("body", ec.Body))
}
if ec.UserAgent != "" {
fields = append(fields, zap.String("user_agent", ec.UserAgent))
}
if ec.UserID != "" {
fields = append(fields, zap.String("user_id", ec.UserID))
}
return fields
}