场景:一个middleware可以具体为一个函数,而由前面的gin 路由分析可得,每一个路径都对有一个HandlersChain 与其对应。

那么实际上增加一个middleware的过程,就是将每一个路由策略加进来之前,与其绑定,这样就能使得这一类的路由到来的时候触发这个中间件生效。

下面看看gin web framework中是如何实现的?

首先是:gin.default()函数

// Default returns an Engine instance with the Logger and Recovery middleware already attached.
func Default() *Engine {
debugPrintWARNINGDefault()
engine := New()
engine.Use(Logger(), Recovery()) #加载Logger(), 和Recovery()中间件
return engine
}

然后查看engine.Use()

// Use attachs a global middleware to the router. ie. the middleware attached though Use() will be
// included in the handlers chain for every single request. Even 404, 405, static files...
// For example, this is the right place for a logger or error management middleware.
func (engine *Engine) Use(middleware ...HandlerFunc) IRoutes {
engine.RouterGroup.Use(middleware...) #这个函数的参数是一个不定参数,也就是说我们可以追加的中间件没有限制
engine.rebuild404Handlers()
engine.rebuild405Handlers()
return engine
}

接着是engine.RouterGroup.Use()

// Use adds middleware to the group, see example code in GitHub.
func (group *RouterGroup) Use(middleware ...HandlerFunc) IRoutes {
group.Handlers = append(group.Handlers, middleware...) #将middleware暂存在group.Handlers中
return group.returnObj()
}

这个时候,我们再来看一个路由信息的调用过程,如,我们定义一个Get的路由

// Ping test
r.GET("/ping", func(c *gin.Context) {
c.String(http.StatusOK, "pong")
})

查看r.GET函数的实现

// GET is a shortcut for router.Handle("GET", path, handle).
func (group *RouterGroup) GET(relativePath string, handlers ...HandlerFunc) IRoutes {
return group.handle("GET", relativePath, handlers) #将handlers 函数以及相对路径传递给group.handle()函数
}

查看group.handle()函数的实现

func (group *RouterGroup) handle(httpMethod, relativePath string, handlers HandlersChain) IRoutes {
absolutePath := group.calculateAbsolutePath(relativePath) #计算绝对路径
handlers = group.combineHandlers(handlers) #将参数的handlers 和 middleware 的handlers拼接在一起作为一条路由信息,传递给addRoute()函数
group.engine.addRoute(httpMethod, absolutePath, handlers)
return group.returnObj()
}

 查看group.combineHandlers()函数的实现

func (group *RouterGroup) combineHandlers(handlers HandlersChain) HandlersChain {
finalSize := len(group.Handlers) + len(handlers)
if finalSize >= int(abortIndex) {
panic("too many handlers")
}
mergedHandlers := make(HandlersChain, finalSize) #创建一个HandlersChain的数组,然后把group.handlers 和 参数的handlers copy 进去
copy(mergedHandlers, group.Handlers)
copy(mergedHandlers[len(group.Handlers):], handlers)
return mergedHandlers
}

 于是每一条路由的达到,如果根据基树找到这里的HandlersChain,那么就会触发该HandlersChain中所有的func, 至于如何找到的,查看gin 启动流程分析这篇文章。

这样的中间件设计有什么优缺点呢?

优点:保证所有的路由信息都会用到中间件。

缺点:如果中间件并不适用于所有的路由策略,则更改起来比较麻烦,需要在中间件内部根据context做判断。

go web framework gin middleware 设计原理的更多相关文章

  1. go web framework gin 路由表的设计

    在上一篇go web framework gin 启动流程分析这一篇文章中,我分析了go gin启动的过程,在这一篇文章中我将继续上面的分析,讨论gin 中路由表是如何设计的? 首先查看engine. ...

  2. go web framework gin group api 设计

    假如让你来设计group api, 你该怎么设计呢? group api 和普通api的区别在于前缀不同,如果group api的版本为v1.0 那么相对应的url为/v1.0/xxx, 如果是普通a ...

  3. go web framework gin 启动流程分析

    最主要的package : gin 最主要的struct: Engine Engine 是整个framework的实例,它包含了muxer, middleware, configuration set ...

  4. html5设计原理(转)

    转自:   http://www.cn-cuckoo.com/2010/10/21/the-design-of-html5-2151.html 今天我想跟大家谈一谈HTML5的设计.主要分两个方面:一 ...

  5. 学习HTML5必读之《HTML5设计原理》

    引子:很久前看过的一遍受益匪浅的文章,今天再次转过来,希望对学习HTML5的朋友有所帮助. 今天我想跟大家谈一谈HTML5的设计.主要分两个方面:一方面,当然了,就是HTML5.我可以站在这儿只讲HT ...

  6. 介绍一个python的新的web framework——karloop框架

    karloop是一款轻型的web framework,和tornado.webpy类似.mvc分层设计,眼下已经公布早期版本号了,使用方便, 下载地址例如以下:https://github.com/k ...

  7. BigPipe设计原理

    高性能页面加载技术--BigPipe设计原理及Java简单实现 1.技术背景 动态web网站的历史可以追溯到万维网初期,相比于静态网站,动态网站提供了强大的可交互功能.经过几十年的发展,动态网站在互动 ...

  8. Jena 简介:通过 Jena Semantic Web Framework 在 Jave 应用程序中使用 RDF 模型

    简介: RDF 越来越被认为是表示和处理半结构化数据的一种极好选择.本文中,Web 开发人员 Philip McCarthy 向您展示了如何使用 Jena Semantic Web Toolkit,以 ...

  9. Web Service进阶(一)运行原理

    利用清明小假期,温习了一遍Web Service的相关内容,对其工作原理进行了简要总结.以供有需求的朋友和自己日后参考.文章若有不当之处,敬请朋友们提出宝贵建议,以求共勉. Web服务中,我们应该首先 ...

随机推荐

  1. keepalived weight正负值问题(实现主服务器nginx故障后迅速切换到备服务器)

    有两台负载均衡,lb01,lb02.  lb02, priority值为100 编辑keepalived配置文件   vim /etc/keepalived/keepalived.conf ! Con ...

  2. m2e-wtp的作用

    描述 Maven3下的项目结构,target目录下会有一个m2e-wtp文件夹,删除掉会自动生成,有什么作用呢? wtp解释 WTP:Web Tools Project Maven集成WTP The ...

  3. Class_fourh_异常总结

    使用try,catch,finally.检查指点检查点是否错误: try里填入监测的内容 catch 小括号里放类型错误  判断try里出现的错误是哪一类错误 中括号里放 输出内容 在控制台上输出错误 ...

  4. Html Title 标签

    Html Title 标签 Title 是 HTML Head 内部标签 <html> <head> <!-- Title标签:HTML的标头标题 --> < ...

  5. docker安装openwrt镜像(不完美案例)

    镜像从http://downloads.openwrt.org/releases下载 注意选择generic-rootfs.tar.gz这种类型的镜像 使用docker import导入镜像,导入后可 ...

  6. ASP.NET MVC:缓存功能的设计及问题

    这是非常详尽的asp.net mvc中的outputcache 的使用文章. [原文:陈希章 http://www.cnblogs.com/chenxizhang/archive/2011/12/14 ...

  7. vijos 1605 双栈排序 - 贪心 - 二分图

    题目传送门 传送门I 传送门II 题目大意 双栈排序,问最小字典序操作序列. 不能发现两个数$a_{j}, a_{k}\ \ (j < k)$不能放在同一个栈的充分必要条件时存在一个$i$使得$ ...

  8. 最短路模板|堆优化Dijkstra,SPFA,floyd

    Ⅰ:Dijkstra单源点最短路 1.1Dijkstra const int MAX_N = 10000; const int MAX_M = 100000; const int inf = 0x3f ...

  9. Anaconda安装mysqldb模块

    在anaconda里mysqldb是封在mysql-python里的,所以要先在anaconda prompt里运行 conda install mysql-python.(注意要右键选管理员身份)有 ...

  10. 使用RStudio调试(debug)基础学习(一)

    点击行号的左侧,即可设置断点(或者按下Shift+F9),如果没有出现,反而出现下图的警告: 那么只是因为我的坏习惯--写一段脚本测试的时候都是新建,但不save到本地,不喜欢保存,写的差不多了才开始 ...