有时候只需要给某个特定路由添加中间件,而不是整个路由组。Gin 支持在单个路由上直接应用中间件。
在路由定义时直接传入中间件:
package main
import (
"net/http"
"github.com/gin-gonic/gin"
)
func Auth() gin.HandlerFunc {
return func(c *gin.Context) {
token := c.GetHeader("Authorization")
if token == "" {
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{
"error": "请先登录",
})
return
}
c.Next()
}
}
func main() {
r := gin.Default()
r.GET("/public", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"message": "公开接口"})
})
r.GET("/profile", Auth(), func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"user": "张三"})
})
r.POST("/settings", Auth(), func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"message": "设置已更新"})
})
r.Run(":8080")
}
单个路由可以应用多个中间件:
func Auth() gin.HandlerFunc {
return func(c *gin.Context) {
fmt.Println("认证中间件")
c.Next()
}
}
func RateLimit() gin.HandlerFunc {
return func(c *gin.Context) {
fmt.Println("限流中间件")
c.Next()
}
}
func Audit() gin.HandlerFunc {
return func(c *gin.Context) {
fmt.Println("审计中间件")
c.Next()
}
}
r.POST("/sensitive", Auth(), RateLimit(), Audit(), func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"message": "敏感操作完成"})
})
执行顺序:Auth → RateLimit → Audit → 处理器
r.GET("/user/profile", Auth(), getUserProfile)
r.PUT("/user/profile", Auth(), updateUserProfile)
r.DELETE("/user/account", Auth(), deleteAccount)
func AdminOnly() gin.HandlerFunc {
return func(c *gin.Context) {
role, _ := c.Get("userRole")
if role != "admin" {
c.AbortWithStatusJSON(http.StatusForbidden, gin.H{
"error": "需要管理员权限",
})
return
}
c.Next()
}
}
r.DELETE("/users/:id", Auth(), AdminOnly(), deleteUser)
r.GET("/admin/stats", Auth(), AdminOnly(), getStats)
func ValidatePost() gin.HandlerFunc {
return func(c *gin.Context) {
var post struct {
Title string `json:"title" binding:"required,min=3"`
Content string `json:"content" binding:"required,min=10"`
}
if err := c.ShouldBindJSON(&post); err != nil {
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{
"error": err.Error(),
})
return
}
c.Set("post", post)
c.Next()
}
}
r.POST("/posts", Auth(), ValidatePost(), createPost)
func ValidateUpload(maxSize int64, allowedTypes []string) gin.HandlerFunc {
return func(c *gin.Context) {
file, err := c.FormFile("file")
if err != nil {
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{
"error": "请选择文件",
})
return
}
if file.Size > maxSize {
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{
"error": "文件过大",
})
return
}
c.Set("uploadedFile", file)
c.Next()
}
}
r.POST("/upload", Auth(), ValidateUpload(5*1024*1024, []string{".jpg", ".png"}), handleUpload)
单路由中间件和路由组中间件可以结合使用:
api := r.Group("/api")
api.Use(Auth())
{
api.GET("/posts", listPosts)
api.POST("/posts", createPost)
api.DELETE("/posts/:id", AdminOnly(), deletePost)
}
/api/posts 只需要 Auth,/api/posts/:id 的删除需要 Auth + AdminOnly。
根据条件选择中间件:
func withOptionalAuth() gin.HandlerFunc {
return func(c *gin.Context) {
token := c.GetHeader("Authorization")
if token != "" {
user, err := validateToken(token)
if err == nil {
c.Set("user", user)
}
}
c.Next()
}
}
r.GET("/posts", withOptionalAuth(), listPosts)
单路由中间件适合只需要在特定接口上应用的逻辑。使用方式很简单,在路由定义时传入中间件函数即可。多个中间件按传入顺序执行。合理组合单路由中间件和路由组中间件,可以灵活控制每个接口的访问策略。