gin middleware
gin middleware
middleware 也就是我们常说的中间件。现在基本上每个
web
框架都会带有中间件的功能,不仅仅是golang
,其他语言的各个框架基本上都有,只是用法不同和抽象程度不一样罢了,像Python中间件的使用形式大都是通过装饰器来实现的,而golang
的中间件从使用的角度上来说可能没有Python来的那么简便,但实现的原理来说都是一样的。中间件听起来好像复杂的一个概念,其实其本质上就是函数包函数,像洋葱一样一层一层的,所以叫做中间件。用各个中间件将逻辑隔离开这种方式会比把所有的功能代码都写在一个函数更容易理解和维护,代码也会更优雅。
gin 的中间件使用
其实我们之前之前再讲gin Context
时候已经简单提过gin
的middleware
了,这里再单独拿出来看看它的中间件功能是怎么实现封装提供出来用的。
r := gin.Default()
上面这行代码初始化了一个默认的gin
engine
,默认的gin engine
其实使用了两个middleware
:
Logger
Recovery
func Default() *Engine { debugPrintWARNINGDefault() engine := New() // new获取一个新的gin engine engine.Use(Logger(), Recovery()) // 在该engine上使用Logger和Recovery 中间件 return engine }
可以看到gin
使用中间件的方式也很简单,调用Use
把想要用的中间传进去就可以了。这里有一个注意的地方是传入Use的中间件参数顺序和执行时候的顺序是一样的,另外也可以对某个路由组单独使用一些中间件,比如一个项目只有某些url
才需要认证过后才能访问,就可以把这些url
分在一个路由组里面然后对这个路由组应用auth
中间件。比如:
//方式一 authorized := router.Group("/", MyMiddelware()) // 或者这样用 authorized := router.Group("/") authorized.Use(MyMiddelware()) { authorized.POST("/login", loginEndpoint) }
另外,还可以对单个路由单独应用中间件,比如:
r := gin.Default() //局部中间键使用 r.GET("/ce", MyMiddleWare(), MyHandler)
gin 中间件的实现
func (group *RouterGroup) Use(middleware ...HandlerFunc) IRoutes { group.Handlers = append(group.Handlers, middleware...) return group.returnObj() }
可以看到,middleware
实际上就是一组HandlerFunc
,这和定义单个路由时定义的处理函数没有任何区别,而Use
做的事情也仅仅是把传入的一组中间件append
进routerGroup.Handlers
数组而已。来看看在注册完路由和中间件之后gin
在接收到了一个请求之后是怎么调用这些middleware
的:
func (engine *Engine) handleHTTPRequest(c *Context) { httpMethod := c.Request.Method rPath := c.Request.URL.Path unescape := false if engine.UseRawPath && len(c.Request.URL.RawPath) > 0 { rPath = c.Request.URL.RawPath unescape = engine.UnescapePathValues } if engine.RemoveExtraSlash { rPath = cleanPath(rPath) } // Find root of the tree for the given HTTP method t := engine.trees for i, tl := 0, len(t); i < tl; i++ { if t[i].method != httpMethod { continue } root := t[i].root // Find route in tree value := root.getValue(rPath, c.params, unescape) if value.params != nil { c.Params = *value.params } if value.handlers != nil { // 这里,如果该路由节点的handlers 不为nil,则将handlers 赋值给context.handlers,然后调用c .Next()
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
<p> <span style="font-size:14px;">本专刊是Go开源项目源码分析专栏,共 17 篇文章,挑选了Go 开源界知名的 4 个开源项目gnet(高效的网络库)、gin(知名的Go微型web框架)、fasthttp(高性能web框架)、nsq(Go消息队列)来对它们进行源码分析,分析它们的设计思想和代码实现。每个项目的讲解都是由浅入深,由设计思想的剖析到源码实现的分析,更易于读者理解。</span> </p> <p> <br /> </p> <h2> <b><span style="font-size:16px;line-height:1;">购买须知:</span></b> </h2> <span style="font-size:14px;">订阅成功后,用户即可通过牛客网 PC 端、App 端享有永久阅读的权限;</span><br /> <span style="font-size:14px;">牛客专刊为虚拟内容服务,订阅成功后概不退款;</span><br /> <span style="font-size:14px;line-height:1;">在专刊阅</span><span style="font-size:14px;line-height:1;">读过程中,如有任何问题,可在文章评论区底部留言,或添加牛客导师,加入读者交流群;</span><br /> <span style="font-size:14px;">想成为牛客作者,请邮件联系yinxiaoxiao@nowcoder.com,邮件主题【牛客作者+写作方向】,并附上个人简历一份及近期作品一份;</span><br /> <p> <span style="font-size:14px;">牛客专刊版权归本平台所有,任何机构、媒体、网站或个人未经本网协议授权不得转载、链接、转贴或以其他方式复制发布 / 发表,违者将依法追究责任</span><span style="font-size:14px;">。</span> </p> <p> <br /> </p>