在处理一个请求的过程中,经常需要在中间件和处理器之间传递数据。Gin 的 Context 提供了
Set和Get方法来实现这个功能。
func middleware() gin.HandlerFunc {
return func(c *gin.Context) {
c.Set("userID", 123)
c.Set("role", "admin")
c.Next()
}
}
func handler(c *gin.Context) {
// 获取值(返回 interface{} 和 bool)
userID, exists := c.Get("userID")
if exists {
fmt.Println(userID.(int))
}
// 使用类型特定的方法
role := c.GetString("role")
count := c.GetInt("count")
}
Context 提供了多种类型的获取方法:
// 获取并断言类型
c.Get(key) // (interface{}, bool)
c.GetString(key) // string
c.GetInt(key) // int
c.GetInt64(key) // int64
c.GetFloat64(key) // float64
c.GetBool(key) // bool
c.GetStringMap(key) // map[string]interface{}
c.GetStringSlice(key) // []string
c.GetTime(key) // time.Time
c.GetDuration(key) // time.Duration
如果值不存在或类型不匹配,这些方法会返回零值。
func authMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
token := c.GetHeader("Authorization")
claims, err := validateToken(token)
if err != nil {
c.AbortWithStatusJSON(401, gin.H{"error": "unauthorized"})
return
}
// 存储用户信息供后续使用
c.Set("userID", claims.UserID)
c.Set("username", claims.Username)
c.Set("role", claims.Role)
c.Next()
}
}
func getUserHandler(c *gin.Context) {
userID := c.GetInt("userID")
username := c.GetString("username")
c.JSON(200, gin.H{
"user_id": userID,
"username": username,
})
}
func requestIDMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
requestID := uuid.New().String()
c.Set("requestID", requestID)
// 也可以设置到响应头
c.Header("X-Request-ID", requestID)
c.Next()
}
}
func logMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
start := time.Now()
c.Next()
requestID := c.GetString("requestID")
log.Printf("[%s] %s %s %d %v",
requestID,
c.Request.Method,
c.Request.URL.Path,
c.Writer.Status(),
time.Since(start),
)
}
}
如果确定值一定存在,可以使用 MustGet,不存在时会 panic:
func handler(c *gin.Context) {
// 如果 userID 不存在,会 panic
userID := c.MustGet("userID").(int)
fmt.Println(userID)
}
建议配合 recovery 中间件使用,或者只在确定值存在的情况下使用。
可以存储任意类型的数据:
type User struct {
ID int
Username string
Email string
}
func middleware() gin.HandlerFunc {
return func(c *gin.Context) {
user := &User{
ID: 1,
Username: "alice",
Email: "alice@example.com",
}
c.Set("user", user)
c.Next()
}
}
func handler(c *gin.Context) {
userInterface, exists := c.Get("user")
if !exists {
c.JSON(401, gin.H{"error": "user not found"})
return
}
user, ok := userInterface.(*User)
if !ok {
c.JSON(500, gin.H{"error": "invalid user type"})
return
}
c.JSON(200, user)
}
func handler(c *gin.Context) {
// 获取所有存储的值
allKeys := c.Keys
for key, value := range allKeys {
fmt.Printf("%s: %v\n", key, value)
}
}
Context 的值存储功能是中间件和处理器之间传递数据的核心机制:
Set 存储值Get 或类型特定的方法获取值这个功能让 Gin 的中间件模式变得非常灵活,可以在请求处理链的任何位置存取数据。