中间件,英译middleware,顾名思义,放在中间的物件,那么放在谁中间呢?原本,客户端能够直接请求到服务端接口。git
如今,中间件横插一脚,它能在请求到达接口以前拦截请求,作一些特殊处理,好比日志记录,故障处理等。这就是今天要讲述的中间件,那么,它在Gin框架中是怎么使用的呢?github
咱们来看一下逢gin
必调的方法Default
,方法中有一个变量engine
,它Use
了Logger
和Recovery
两个函数,这两个函数就是gin
框架的日志和故障处理中间件。golang
func Default() *Engine {
debugPrintWARNINGDefault()
engine := New()
engine.Use(Logger(), Recovery())
return engine
}复制代码
那就很清楚了,使用中间件就是调用Use
方法就好了呗,问题是如今除了这两个中间件还能去Use
谁?不如咱先本身写一个中间件吧,这样比较容易理解。浏览器
写啥呢,作产品讲究MVP,那咱就写个最简单的闭环,拦截请求后输出平也最帅
的日志,产品就能够交付了。markdown
写以前先研究一下官方的Logger
和Recovery
是怎么写的,比如葫芦画瓢。cookie
func Logger() HandlerFunc {
return LoggerWithConfig(LoggerConfig{})
}
func Recovery() HandlerFunc {
return RecoveryWithWriter(DefaultErrorWriter)
}复制代码
原来这两个函数都返回了HandlerFunc
类型,那咱们也模仿写一个函数就行了。框架
func PingYe() gin.HandlerFunc {
return func(c *gin.Context) {
c.String(200, "平也最帅")
}
}复制代码
很简单,写完了,能够在main
函数中Use
它了。函数
func main() {
r := gin.Default()
r.Use(PingYe())
r.Run()
}复制代码
把项目跑起来,访问localhsot:8080
看一下,帅呆了,成功渲染数据。oop
是否是太简单了?这就交差了?我还能打十个啊!?编码
看来我要把毕生所学都交给你了。
假如咱们定义了两个中间件,一个是平也最帅,另外一个是在哪里最帅。
func PingYe() gin.HandlerFunc {
return func(c *gin.Context) {
c.String(200, "平也最帅")
}
}
func Where() gin.HandlerFunc {
return func(c *gin.Context) {
c.String(200, "在全宇宙")
}
}复制代码
按顺序把它们分别注册到框架当中,这个时候咱们猜想它会先输出平也最帅
再输出在全宇宙
对吧?对,确实是的。
func main() {
r := gin.Default()
r.Use(PingYe(), Where())
r.Run()
}复制代码
可是,若是我在不更改注册顺序的前提下,怎么调换一下顺序,先输出在全宇宙
再输出平也最帅
呢?这就用到了大名鼎鼎的Next
方法。它的做用就是先执行如下一个中间件,执行完了再回来继续执行接下来的逻辑。记得是在中间件中调用哦~
func PingYe() gin.HandlerFunc {
return func(c *gin.Context) {
c.Next()
c.String(200, "平也最帅")
}
}复制代码
固然,除了提供Next
方法外,理论上也应该有个中断操做吧,毕竟拿中间件来作受权验证的话,验证失败后仍是但愿阻断请求的。因此,Abort
就是咱们要找的那个方法。拿上面的例子,在平也最帅
的下一行调用Abort
方法后,Where
中间件就再也不生效了,因而平也只剩下了单纯的帅气。
func PingYe() gin.HandlerFunc {
return func(c *gin.Context) {
c.String(200, "平也最帅")
c.Abort()
}
}复制代码
刚才我讲的中间件是会在全部的路由上生效的,有些不须要添加中间件的路由场景就没法适应了。因此,咱们须要有能为局部添加中间件的能力。
咱们先实现给某个接口单独加中间件,因此先得定义两个接口know
与unknown
,分别表明认识平也与不认识两个场景,鉴于认识后才知道平也是全宇宙最帅的,因此要绑中间件,不认识就算了。实现方式很是简单,往路由后面的参数拼命加中间件就行了。
r.GET("know", PingYe(), Where())
r.GET("unknown", func(c *gin.Context) {
c.String(200, "???")
})复制代码
除了针对某个接口添加中间件外,还能够针对一组接口添加,一样调用Use
方法便可。
v1 := r.Group("v1")
v1.Use(PingYe(), Where())
{
v1.GET("/know", func(c *gin.Context) {
c.String(200, "know")
})
v1.GET("/unknown", func(c *gin.Context) {
c.String(200, "unknown")
})
}复制代码
基本认证,又称BasicAuth
,加了基本认证的接口,会让你在访问接口时提供用户名与密码。
对于浏览器用户,为了用户的体验会自动弹出登陆框,而在其余场景下是没有的,那在哪里输入帐号密码呢?实际上,它是经过头信息传输的,头信息里有一个固定的格式来表明基本认证。
Authorization: Basic <凭证>复制代码
凭证部分是是用户名和密码组合的base64
编码,二者以冒号方式拼接。然鹅,gin
框架的BaseAuth
中间件早已准备好了一切,它能够短短几行代码就能解析基本认证的信息。
func main() {
r := gin.Default()
r.Use(gin.BasicAuth(gin.Accounts{
"pingye": "123",
}))
r.GET("/secrets", func(c *gin.Context) {
user := c.MustGet(gin.AuthUserKey).(string)
c.String(200, user+"已登陆成功")
})
r.Run()
}复制代码
示例中的部分代码可能有些同窗不太明白,好比BasicAuth
方法中的参数,由于基本认证须要帐号和密码对吧,因此咱们能够利用gin.Accounts
方便的配置好须要验证的帐号密码,gin.Accounts
是一个map类型,键表明用户名,值表明密码,固然能够设置不止一个键值对,根据你的喜爱自行设置。
代码中还出现了c.MustGet
方法,这个方法的做用就是必定要取到某个参数,取不到就不干了panic
,取的是什么呢?就是gin.AuthUserKey
,在官方中的解释是基本认证中用户凭证的cookie
名称。
// AuthUserKey is the cookie name for user credential in basic auth.
const AuthUserKey = "user"复制代码
Go语言库示例开源项目「golang-examples」欢迎star~
https://github.com/pingyeaa/golang-examples复制代码
感谢你们的观看,若是以为文章对你有所帮助,欢迎关注公众号「平也」,聚焦Go语言与技术原理。
若是你以为文章对你有所帮助,给我点个赞哦~