在 Gin 框架中,中間件是一種對請求進行預處理或攔截的機制。中間件可以用來實現很多功能,比如身份驗證、請求日誌記錄、請求參數驗證等。在 Gin 中,中間件可以是一個函數或一個結構體。
下面分別介紹這兩種中間件類型,並給出例子。
- 函數式中間件
函數式中間件是一個接受 gin.HandlerFunc 作爲參數的函數。它可以在請求被處理之前或之後執行一些操作,比如記錄日誌、驗證身份等。
下面是一個示例,演示如何實現一個記錄請求日誌的中間件:
func Logger() gin.HandlerFunc {
return func(c *gin.Context) {
start := time.Now()
// 處理請求
c.Next()
// 記錄日誌
latency := time.Since(start)
log.Printf("[%s] %s %s %v", c.Request.Method, c.Request.URL.Path, c.Request.RemoteAddr, latency)
}
}
// 使用中間件
router := gin.Default()
router.Use(Logger())
這個中間件會記錄每個請求的 HTTP 方法、URL、遠程地址和處理時間等信息,並將它們輸出到日誌中。
- 結構體中間件
結構體中間件是一個實現了 gin.HandlerFunc 接口的結構體。它可以包含一些成員變量和方法,用於在請求被處理之前或之後執行一些操作。
下面是一個示例,演示如何實現一個基於 JWT 的身份驗證中間件
type AuthMiddleware struct {
JWTSecret []byte
}
func (m *AuthMiddleware) MiddlewareFunc() gin.HandlerFunc {
return func(c *gin.Context) {
// 從請求頭中獲取 token
tokenStr := c.GetHeader("Authorization")
if tokenStr == "" {
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "missing token"})
return
}
// 解析 token
token, err := jwt.ParseWithClaims(tokenStr, &jwt.StandardClaims{}, func(token *jwt.Token) (interface{}, error) {
return m.JWTSecret, nil
})
if err != nil {
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "invalid token"})
return
}
// 驗證 token
if !token.Valid {
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "invalid token"})
return
}
// 將用戶信息保存到上下文中
claims := token.Claims.(*jwt.StandardClaims)
c.Set("user_id", claims.Subject)
// 處理請求
c.Next()
}
}
// 使用中間件
router := gin.Default()
auth := &AuthMiddleware{JWTSecret: []byte("secret")}
router.Use(auth.MiddlewareFunc())
這個中間件會從請求頭中獲取 JWT token,並驗證它是否合法。如果 token 驗證通過,則將用戶信息保存到上下文中,並讓請求繼續處理。如果驗證不通過,則返回一個 HTTP 401 響應。
- 多個函數式中間件組成的中間件鏈
func AuthMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
// ...
}
}
func LoggerMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
// ...
}
}
// 使用中間件鏈
router := gin.Default()
router.Use(LoggerMiddleware(), AuthMiddleware())
這個示例演示瞭如何使用多個函數式中間件組成的中間件鏈。中間件鏈中的中間件按照順序依次執行,即 LoggerMiddleware() 執行完之後再執行 AuthMiddleware()。
- 分組中間件
func GroupAuthMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
// ...
}
}
func GroupHandler() gin.HandlerFunc {
return func(c *gin.Context) {
// ...
}
}
// 使用分組中間件
router := gin.Default()
group := router.Group("/", GroupAuthMiddleware())
group.GET("/", GroupHandler())
這個示例演示瞭如何使用分組中間件。分組中間件只會對分組中的路由生效,而不會對全局路由生效。
- 基於路由的中間件
func RouteMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
// ...
}
}
// 使用基於路由的中間件
router := gin.Default()
router.GET("/", RouteMiddleware(), func(c *gin.Context) {
// ...
})
- 基於 HTTP 方法的中間件
func GetMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
// ...
}
}
// 使用基於 HTTP 方法的中間件
router := gin.Default()
router.GET("/", GetMiddleware(), func(c *gin.Context) {
// ...
})
這個示例演示瞭如何使用基於 HTTP 方法的中間件。基於 HTTP 方法的中間件只會對指定的 HTTP 方法生效,而不會對其他 HTTP 方法生效。