不是所有中间件都需要全局生效,路由组中间件让你可以精确控制中间件的作用范围。
路由组使用 Group() 创建,可以给整个组添加中间件:
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()
api := r.Group("/api")
api.Use(Auth())
{
api.GET("/profile", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"user": "张三"})
})
api.GET("/settings", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"theme": "dark"})
})
}
r.GET("/public", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"message": "公开接口"})
})
r.Run(":8080")
}
/api/profile 和 /api/settings 都需要认证,/public 不需要。
不同路由组可以有不同的中间件:
func AdminAuth() gin.HandlerFunc {
return func(c *gin.Context) {
role := c.GetHeader("X-Role")
if role != "admin" {
c.AbortWithStatusJSON(http.StatusForbidden, gin.H{
"error": "需要管理员权限",
})
return
}
c.Next()
}
}
func UserAuth() 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()
admin := r.Group("/admin")
admin.Use(AdminAuth())
{
admin.GET("/users", listUsers)
admin.DELETE("/users/:id", deleteUser)
}
user := r.Group("/user")
user.Use(UserAuth())
{
user.GET("/profile", getProfile)
user.PUT("/profile", updateProfile)
}
public := r.Group("/public")
{
public.GET("/info", getPublicInfo)
}
r.Run(":8080")
}
路由组可以嵌套,中间件会叠加:
func main() {
r := gin.Default()
api := r.Group("/api")
api.Use(Logger())
{
v1 := api.Group("/v1")
v1.Use(Auth())
{
v1.GET("/posts", listPosts)
v1.POST("/posts", createPost)
admin := v1.Group("/admin")
admin.Use(AdminAuth())
{
admin.GET("/stats", getStats)
}
}
v2 := api.Group("/v2")
v2.Use(Auth(), RateLimit())
{
v2.GET("/posts", listPostsV2)
}
}
r.Run(":8080")
}
/api/v1/admin/stats 会经过 Logger → Auth → AdminAuth 三个中间件。
中间件可以通过 c.Set() 传递数据给处理器:
func ParseUser() gin.HandlerFunc {
return func(c *gin.Context) {
token := c.GetHeader("Authorization")
user, err := parseToken(token)
if err != nil {
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{
"error": "无效的令牌",
})
return
}
c.Set("currentUser", user)
c.Next()
}
}
api := r.Group("/api")
api.Use(ParseUser())
{
api.GET("/me", func(c *gin.Context) {
user, exists := c.Get("currentUser")
if !exists {
c.JSON(http.StatusInternalServerError, gin.H{"error": "用户信息丢失"})
return
}
c.JSON(http.StatusOK, user)
})
}
根据条件动态创建路由组:
func setupRoutes(r *gin.Engine, config *Config) {
api := r.Group("/api")
if config.EnableAuth {
api.Use(Auth())
}
if config.EnableRateLimit {
api.Use(RateLimit())
}
api.GET("/data", getData)
}
func ListMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
c.Next()
}
}
func CreateMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
c.Next()
}
}
api := r.Group("/api")
api.Use(ListMiddleware())
{
api.GET("/items", listItems)
create := api.Group("/")
create.Use(CreateMiddleware())
{
create.POST("/items", createItem)
}
}
路由组中间件让你可以精确控制中间件的作用范围,避免全局中间件带来的性能开销。嵌套路由组时,中间件会按层级叠加。合理组织路由组和中间件,可以让代码结构更清晰。