学校网站建设培训心得,郑州市建设教育协会网站,网站后台登录系统是怎么做的,网站建设可用性的五个方面Go web框架——Gin中间件与路由 1 单独注册中间件1.1 入门案例1.2 多个中间件1.3 中间件拦截响应1.4 中间件放行 2 全局注册中间件3 自定义参数传递4 路由分组4.1 入门案例4.2 路由分组注册中间件4.3 综合使用 5 使用内置的中间件6 中间件案例权限验证耗时统计 1 单独注册中间件… Go web框架——Gin中间件与路由 1 单独注册中间件1.1 入门案例1.2 多个中间件1.3 中间件拦截响应1.4 中间件放行 2 全局注册中间件3 自定义参数传递4 路由分组4.1 入门案例4.2 路由分组注册中间件4.3 综合使用 5 使用内置的中间件6 中间件案例权限验证耗时统计 1 单独注册中间件
Gin框架允许开发者在处理请求的过程中加入用户自己的钩子Hook函数。这个钩子函数就叫中间件中间件适合处理一些公共的业务逻辑比如登录认证、权限校验、数据分页、记录日志、耗时统计等 即比如如果访问一个网页的话不管访问什么路径都需要进行登录此时就需要为所有路径的处理函数进行统一一个中间件
Gin中的中间件必须是一个gin.HandlerFunc类型
1.1 入门案例
我们先看一下Get函数能够接收的参数
func (group *RouterGroup) GET(relativePath string, handlers ...HandlerFunc) IRoutes {return group.handle(http.MethodGet, relativePath, handlers)
}type HandlerFunc func(*Context)从这个函数里我们能看到它可以它可以接收很多的HandlerFunc类型的数据并且发现是func(*Context)数据类型都可以所以我们可以定义很多个中间件它必须是*gin.Context类型
定义一个中间件
func m1(c *gin.Context) {fmt.Println(m1 in.........)
}写一个函数在前端响应的数据作为参考
func indexHandler(c *gin.Context) {fmt.Println(index.....)c.JSON(http.StatusOK, gin.H{msg: index,})
}完整代码
func indexHandler(c *gin.Context) {fmt.Println(index.....)c.JSON(http.StatusOK, gin.H{msg: index,})
}// 定义一个中间件
func m1(c *gin.Context) {fmt.Println(m1 in.........)
}func main() {r : gin.Default()//m1处于indexHandler函数的前面,请求来之后,先走m1,再走indexr.GET(/index, m1, indexHandler)r.Run(:8000)
}注意m1处于indexHandler函数的前面,请求来之后,先走m1再走index
然后使用游览器访问对应的请求看一下输出 验证完毕~
1.2 多个中间件
router.GET后面可以跟很多HandlerFunc方法这些方法其实都可以叫中间件
package mainimport (fmtgithub.com/gin-gonic/gin
)func m1(c *gin.Context) {fmt.Println(m1 ...in)
}
func m2(c *gin.Context) {fmt.Println(m2 ...in)
}func main() {router : gin.Default()router.GET(/, m1, func(c *gin.Context) {fmt.Println(index ...)c.JSON(200, gin.H{msg: 响应数据})}, m2)router.Run(:8080)
}这里就不演示了~~
1.3 中间件拦截响应
c.Abort()函数作用拦截后续的HandlerFunc就不会执行了
package mainimport (fmtgithub.com/gin-gonic/gin
)func m1(c *gin.Context) {fmt.Println(m1 ...in)c.JSON(200, gin.H{msg: 第一个中间件拦截了})c.Abort()
}
func m2(c *gin.Context) {fmt.Println(m2 ...in)
}func main() {router : gin.Default()router.GET(/, m1, func(c *gin.Context) {fmt.Println(index ...)c.JSON(200, gin.H{msg: 响应数据})}, m2)router.Run(:8080)
}运行后去游览器试一下会发现只输出m1 …in也就是被第一个拦截器拦截了~
1.4 中间件放行
c.Next()函数作用Next前后形成了其他语言中的请求中间件和响应中间件
package mainimport (fmtgithub.com/gin-gonic/gin
)func m1(c *gin.Context) {fmt.Println(m1 ...in)c.Next()fmt.Println(m1 ...out)
}
func m2(c *gin.Context) {fmt.Println(m2 ...in)c.Next()fmt.Println(m2 ...out)
}func main() {router : gin.Default()router.GET(/, m1, func(c *gin.Context) {fmt.Println(index ...in)c.JSON(200, gin.H{msg: 响应数据})c.Next()fmt.Println(index ...out)}, m2)router.Run(:8080)
}输出结果
m1 ...in
index ...in
m2 ...in
m2 ...out
index ...out
m1 ...out 输出的方式有点像栈先进去的m1...out最后再输出~
2 全局注册中间件
在Gin框架中可以使用Use方法注册全局中间件。全局中间件会对所有的请求都生效。
func main() {r : gin.Default()r.Use(Logger()) // 注册全局中间件r.GET(/hello, HelloHandler)r.Run(:8080)
}// Logger 是一个全局中间件
func Logger() gin.HandlerFunc {return func(c *gin.Context) {start : time.Now()c.Next()end : time.Now()latency : end.Sub(start)log.Printf([%s] %s %s %v, c.Request.Method, c.Request.URL.Path, c.Request.RemoteAddr, latency)}
}func HelloHandler(c *gin.Context) {c.String(http.StatusOK, Hello, Gin!)
}在上面的示例中Logger函数是一个全局中间件。它在处理请求之前记录了请求的相关信息并在请求处理完成后打印了请求的耗时。
3 自定义参数传递
在中间件之间传递自定义参数是一种常见的需求。在Gin框架中可以使用Context.Set和Context.Get方法来传递自定义参数并且传递的数据是一个key-value
func main() {r : gin.Default()r.Use(AddCustomData(custom data))r.GET(/hello, HelloHandler)r.Run(:8080)
}func AddCustomData(data string) gin.HandlerFunc {return func(c *gin.Context) {c.Set(customData, data) // 设置自定义参数c.Next()}
}func HelloHandler(c *gin.Context) {customData, exists : c.Get(customData) // 获取自定义参数if exists {c.String(http.StatusOK, Hello, Gin! Custom data: %s, customData)} else {c.String(http.StatusOK, Hello, Gin!)}
}在上面的示例中AddCustomData函数返回了一个中间件函数用于在Context中设置自定义参数。在HelloHandler处理函数中通过Context.Get方法获取自定义参数并使用。
4 路由分组
4.1 入门案例
将一系列的路由放到一个组下统一管理。例如以下的路由前面统一加上api的前缀
package mainimport github.com/gin-gonic/ginfunc main() {router : gin.Default()r : router.Group(/api)r.GET(/index, func(c *gin.Context) {c.String(200, index)})r.GET(/home, func(c *gin.Context) {c.String(200, home)})router.Run(:8080)
}4.2 路由分组注册中间件
package mainimport (fmtgithub.com/gin-gonic/gin
)func middle(c *gin.Context) {fmt.Println(middle ...in)
}func main() {router : gin.Default()r : router.Group(/api).Use(middle) // 可以链式也可以直接r.Use(middle)r.GET(/index, func(c *gin.Context) {c.String(200, index)})r.GET(/home, func(c *gin.Context) {c.String(200, home)})router.Run(:8080)
}这样写我们就可以指定哪一些分组下可以使用中间件了
当然中间件还有一种写法就是使用函数加括号的形式
package mainimport (fmtgithub.com/gin-gonic/gin
)func middle(c *gin.Context) {fmt.Println(middle ...in)
}
func middle1() gin.HandlerFunc {// 这里的代码是程序一开始就会执行return func(c *gin.Context) {// 这里是请求来了才会执行fmt.Println(middle1 ...inin)}
}func main() {router : gin.Default()r : router.Group(/api).Use(middle, middle1())r.GET(/index, func(c *gin.Context) {c.String(200, index)})r.GET(/home, func(c *gin.Context) {c.String(200, home)})router.Run(:8080)
}4.3 综合使用
设置了一个中间件进行身份验证并且还对路由进行分组分为两组来使用
func main() {r : gin.Default()r.Use(Logger()) // 注册全局中间件v1 : r.Group(/v1)v1.Use(Auth()) // 注册 v1 路由组的局部中间件{v1.GET(/hello, HelloHandler)v1.GET(/user, UserHandler)}r.GET(/hello, HelloHandler) // 其他路由不使用 Auth 中间件r.Run(:8080)
}func Auth() gin.HandlerFunc {return func(c *gin.Context) {// 进行身份验证的逻辑if IsAuthenticated {c.Next()} else {c.AbortWithStatus(http.StatusUnauthorized)}}
}func HelloHandler(c *gin.Context) {c.String(http.StatusOK, Hello, Gin!)
}func UserHandler(c *gin.Context) {c.String(http.StatusOK, User Info)
}// Logger 是一个全局中间件
func Logger() gin.HandlerFunc {return func(c *gin.Context) {start : time.Now()c.Next()end : time.Now()latency : end.Sub(start)log.Printf([%s] %s %s %v, c.Request.Method, c.Request.URL.Path, c.Request.RemoteAddr, latency)}
}5 使用内置的中间件
Gin框架内置了一些常用的中间件可以直接使用。以下是一些常用的内置中间件和示例
gin.Logger()记录请求日志gin.Recovery()处理请求时的恢复机制
func main() {r : gin.Default()r.Use(gin.Logger()) // 使用 gin.Logger() 中间件r.Use(gin.Recovery()) // 使用 gin.Recovery() 中间件r.GET(/hello, HelloHandler)r.Run(:8000)
}func HelloHandler(c *gin.Context) {c.String(http.StatusOK, Hello, Gin!)
}不过平常我们不使用这两个中间件的时候一样会有记录所以我们看一下gin.Default函数。
func Default() *Engine {debugPrintWARNINGDefault()engine : New()engine.Use(Logger(), Recovery())return engine
}从这段代码就可以看出是默认使用了这两个函数一般自动调用了~~~
6 中间件案例
权限验证
以前后端最流行的jwt为例如果用户登录了前端发来的每一次请求都会在请求头上携带上token
后台拿到这个token进行校验验证是否过期是否非法
如果通过就说明这个用户是登录过的
不通过就说明用户没有登录
package mainimport (github.com/gin-gonic/gin
)func JwtTokenMiddleware(c *gin.Context) {// 获取请求头的tokentoken : c.GetHeader(token)// 调用jwt的验证函数if token 1234 {// 验证通过c.Next()return}// 验证不通过c.JSON(200, gin.H{msg: 权限验证失败})c.Abort()
}func main() {router : gin.Default()api : router.Group(/api)apiUser : api.Group(){apiUser.POST(login, func(c *gin.Context) {c.JSON(200, gin.H{msg: 登录成功})})}apiHome : api.Group(system).Use(JwtTokenMiddleware){apiHome.GET(/index, func(c *gin.Context) {c.String(200, index)})apiHome.GET(/home, func(c *gin.Context) {c.String(200, home)})}router.Run(:8080)
}耗时统计
统计每一个视图函数的执行时间
func TimeMiddleware(c *gin.Context) {startTime : time.Now()c.Next()since : time.Since(startTime)// 获取当前请求所对应的函数f : c.HandlerName()fmt.Printf(函数 %s 耗时 %d\n, f, since)
}