Gin 的基本使用(下) | 青训营

83 阅读2分钟

路由分离

上篇内容我们讲了该怎么定义路由和控制器,但是在实践中很显而易见的问题是,随着我们的路由数量增加,业务逻辑的复杂,把全部的路由放在 main 函数里,肯定会导致代码臃肿,且耦合度较高,维护起来比较复杂。所以我们需要进行路由的分离。

路由的分离听起来挺玄乎,其实就是将我们前面的路由代码抽离出来,单独放在一个文件中,并用函数对外暴露,然后再主函数中进行调用。从而实现在主函数中初始化路由,而真正的路由配置代码都在单独的文件中。

// router.go
func InitRouter(r *gin.Engine) {
    r.GET("/hello", controller.HelloController)
}

// main.go
func main() {
    r := gin.Default()
    router.InitRouter(r)
    r.Run()
}

路由分组

更进一步的,如果我们关于用户的操作有许多类似的 URL,比如/user/get/user/add等,如果我们一个个的写不仅稍微有点麻烦,主要还是逻辑上不够合理。因为很显然,这些路由是具有相关性的,应当被当做一个路由组来进行处理。

func InitRouter(router *gin.Engine) {  
    rc := router.Group("/user")  
    {  
        rc.GET("/all", controller.UserList)  
        rc.POST("/action", controller.UserAction)  
        rc.GET("/follow", controller.FollowList)  
        rc.GET("/follower", controller.FollowerList)  
        rc.GET("/friend", controller.FriendList)  
    }  
}

中间件

上次讲到在路由里可以传入控制器函数,对请求进行处理并返回数据。那么中间件就是在控制器进行处理前进行中间操作的函数,也就是我们认识的拦截器。

中间件和前面的控制器一样都是gin.HandlerFunc类型的函数,一般来讲我们也在单独的文件中定义以进行代码解耦合。

func AuthMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        authToken := c.DefaultQuery("token", "")
        if authToken == "" {
                authToken = c.PostForm("token")
        }
        // do something before

        // next middleware or controller
        c.Next()
        
        // do something after
    }
}

中间件我们可以用洋葱模型来理解。

k3u1fbpfcp-zoom-in-crop-mark_1512_0_0_0.png

外层就是我们写的 before 和 after 的逻辑,一层层的进来,再一层层的出去。

注意如果在中间件中使用 goroutine 的话,要将 context 的副本传入 goroutine,而不能直接传 context 的引用,可以用 c.Copy() 获取副本。

中间件可以是全局的,也可以某个路由的。而如果某个路由组都需要此中间件,也可以在定义路由组时直接使用。

r := gin.New()

// 全局中间件
r.Use(AuthMiddleware())

// 某个路由的中间件
func MiddlewareHandler1(c *gin.Engine) {
    // do something before
    
    c.Next()
    
    // do something after
}
func MiddlewareHandler2(c *gin.Engine) {
    // do something before
    
    c.Next()
    
    // do something after
}
// 可以使用多个中间件
r.GET("/hello", MiddlewareHandler1, MiddlewareHandler2, controller.HelloController)

// 路由组中间件
rc := r.Group("/user")

rc.Use(AuthMiddleware())
{
    rc.POST("/login", controller.LoginController)
}