中间件性能优化与注意事项
中间件是 Gin 请求处理链的核心,优化其性能对整体应用至关重要。
性能优化策略
1. 减少不必要的中间件
Go
// ❌ 不推荐:全局注册不必要的中间件
r.Use(corsMiddleware())
r.Use(loggerMiddleware())
r.Use(authMiddleware()) // 公共接口不需要认证
// ✅ 推荐:按需注册
r.Use(corsMiddleware())
r.Use(loggerMiddleware())
// 认证中间件只应用于需要认证的路由组
authGroup := r.Group("/api/auth")
authGroup.Use(authMiddleware())
2. 避免重复操作
Go
// ❌ 每次请求都解析 token
func authMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
token := c.GetHeader("Authorization")
claims, _ := parseToken(token) // 每次都解析
c.Set("user_id", claims.UserID)
c.Next()
}
}
// ✅ 使用缓存或预解析
func authMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
token := c.GetHeader("Authorization")
if token == "" {
c.AbortWithStatus(401)
return
}
// 只解析必要部分
userID := extractUserID(token)
c.Set("user_id", userID)
c.Next()
}
}
3. 并行处理
Go
// 并行执行不依赖的中间件逻辑
func parallelMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
var wg sync.WaitGroup
// 并行获取用户信息和权限
wg.Add(2)
var userInfo UserInfo
var permissions []string
go func() {
defer wg.Done()
userInfo = getUserInfo(c)
}()
go func() {
defer wg.Done()
permissions = getPermissions(c)
}()
wg.Wait()
c.Set("user", userInfo)
c.Set("permissions", permissions)
c.Next()
}
}
内存优化
避免大对象存储
Go
// ❌ 存储大对象
func heavyMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
data := loadLargeData() // 大数据
c.Set("data", data) // 占用内存
c.Next()
}
}
// ✅ 只存储必要信息
func lightMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
dataID := getDataID(c)
c.Set("data_id", dataID) // 只存 ID
c.Next()
}
}
使用指针传递
Go
type RequestContext struct {
UserID int
Role string
TraceID string
}
func contextMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
ctx := &RequestContext{ // 使用指针
UserID: 123,
Role: "admin",
TraceID: generateTraceID(),
}
c.Set("ctx", ctx)
c.Next()
}
}
注意事项
1. c.Next() 后的代码仍执行
Go
func loggingMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
start := time.Now()
c.Next() // 执行后续处理
// 这里仍会执行!
duration := time.Since(start)
log.Printf("请求耗时: %v", duration)
}
}
2. c.Abort() 不终止当前中间件
Go
func authMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
if !isAuthenticated(c) {
c.AbortWithStatus(401)
// 当前函数继续执行
log.Println("认证失败")
return // 需要手动 return
}
c.Next()
}
}
3. 错误传递使用 c.Error
Go
func errorMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
c.Next()
// 检查是否有错误
if len(c.Errors) > 0 {
// 统一处理错误
c.JSON(500, gin.H{
"errors": c.Errors,
})
}
}
}
4. Context 不要跨请求传递
Go
// ❌ 错误:保存 Context 到全局变量
var savedContext *gin.Context
func badMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
savedContext = c // 危险!
c.Next()
}
}
// ✅ 正确:只在当前请求内使用
func goodMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
// 仅在当前请求有效
c.Set("request_time", time.Now())
c.Next()
}
}
性能监控
Go
func performanceMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
start := time.Now()
c.Next()
duration := time.Since(start)
// 慢请求告警
if duration > 100*time.Millisecond {
log.Printf("慢请求: %s %s %v",
c.Request.Method, c.Request.URL.Path, duration)
}
}
}
中间件顺序影响性能,日志和监控放在最前,认证放在业务逻辑前。
要点总结
- 减少全局中间件,按路由组精准注册
- 避免重复计算,使用缓存或预解析
- 只在 Context 存储必要信息,避免内存浪费
c.Abort()后需手动 return 终止当前函数- Context 不要跨请求传递,存在并发问题
- 慢请求监控放最后,记录完整处理时间
📝 发现内容有误?点击此处直接编辑