[ GO语言中间件 | 青训营笔记 ]

66 阅读2分钟

全局中间件作用于所有的路由上,所有的路由请求都需要经过这些全局中间件。gin本身提供了一些基础的中间件使用router := gin.Default()定义route时,默认带了Logger()和Recovery()。我们可以使用BasicAuth()中间件做一些简单的用户权限的认证,但是当我们使用了自定义的session时,gin自带的中间件已经不能满足需求。这时,可以编写自定义的中间件并且将自定义的中间件加入到全局中间件队列中去。每一个route的请求同样会到自定义的中间件去,实现自定义的认证等。那么怎么定义一个gin的中间件,这需要实现一个函数,其返回值是func(*Context),下面是gin源码中HandleFunc的描述。通常的做法是在定义的中间件中用闭包的形式返回业务函数。gin提供了两个函数Abort()和Next(),配合着return关键字用来跳转或者终止存在着业务逻辑关系的中间件。1. next()函数会跳过当前中间件中next()后的逻辑,当下一个中间件执行完成后再执行剩余的逻辑

2.abort()函数执行终止当前中间件以后的中间件执行,但是会执行当前中间件的后续逻辑 如果在java里面,我们可以用aop织如一个切面,来完成这个功能,那么在go里面呢?其实开发中,很多这样的问题。这些功能其实和业务不相关,但是这些信息需要统计。比如日志功能,服务渗透率统计,鉴权这些。其实这些东西和业务不是很相关,这里可以用中间件来剥离这些非业务逻辑,来完成功能的拓展。思考了java的aop实现,其实就是一种动态代理,核心要点就是使用了代理模式,所以可以参考这个逻辑,设计go语言里面的代理逻辑。package main

import ( "log" "net/http" "os" "time" ) var logger = log.New(os.Stdout, "", 0) func hello(wr http.ResponseWriter,r *http.Request){ status,err:=wr.Write([]byte("hello,world")) if err!=nil{ log.Print("write fail:%v",err) }else{ log.Println("success: ",status) }

} func timeMiddleware(next http.HandlerFunc)http.Handler{ return http.HandlerFunc(func(wr http.ResponseWriter, r *http.Request) { timeStart:=time.Now() // 业务逻辑 next.ServeHTTP(wr,r)

timeElapsed:=time.Since(timeStart) logger.Println(timeElapsed) }) } func main(){ http.Handle("/hello",timeMiddleware(hello)) err:=http.ListenAndServe(":9999",nil) if err!=nil{ log.Println("hand fail:%v",err) } } 可以看到,这种模式就是可以很好地剥离出业务逻辑。但是这种写法并不是很优雅。其实可以看到,其实中间件就是一个函数,返回了一个处理函数,这个函数可以被说是代理函数。下面用gin框架怎么使用中间件为例,说明真实的开发中,是怎么使middleware的。 综上来看,go语言的中间件更多地关注性能,而Java业务开发更多关注功能的实现,两项都是热门的科技领域,各有各的优点。