本文正在参加 「金石计划 . 瓜分6万现金大奖」
本次主要是聊聊关于 web 中间件, 分为如下四个方面
- 什么是 web 结构中间件
- 为什么要运用 web 中间件
- 怎么运用及其原理
- 哪些场景需求运用中间件
开门见山 web 中间件是啥
Web 结构中的中间件主要指的是在 web 恳求到详细路由之前或许之后,会经过一个或许多个组件进行处理一些必要的公共逻辑(事务相关或许与事务无关的),而处理这些事项的部分,就称为 web 中间件
那是否会有这样的疑问?
分明就能直接恳求到详细的路由,为什么要在它之前加一个中间件?
这是在增加程序复杂度?有啥工作不能直接在路由中做的吗?
咱们能够带着这个问题持续往下看
为什么要运用中间件
一般许多技能或许许多组件大多是因为现有的工具无法满足日益正常的需求而慢慢呈现的
例如
在 web 中需求对多个路由或许事务进行解耦,或许需求在多个路由之前或许之后加上一些一致的逻辑,这个时分就需求中间件来进行处理
又例如
咱们的 web 服务需求有限流功用
假如咱们 web 结构中只有几个路由,那么很简略,可能你会去对每个路由进行限流,那么假如是到达几十上百个路由你还会这样做吗?
假如已经有几十上百个路由了,需求针对所有路由计算一下程序处理时长,那么,这个时分你会去给这些路由一个一个的去复制粘贴代码吗?
正常人天然是不会的,咱们会想办法寻求简略高效且保证质量的方式,分明运用一个中间件就能搞定的工作,何须去做无意义的卷王
多多进步功率去做更多有意义的工作不香吗?
中间件怎么运用及其原理
此处咱们运用大名鼎鼎的高性能 web 结构 Gin 结构来举例子,运用 Gin 结构
Gin 中的中间件实践上便是一个 RouterGroup 对应的 handers 调用链 ,咱们先来看一个例子,自定义两个最简略的中间件,先写一个 main
func main() {
log.SetFlags(log.Lshortfile)
r := gin.New()
r.Use(Demo2())
r.Use(Demo1())
r.GET("/test", func(c *gin.Context) {
log.Println("----inner test----")
c.JSON(200, gin.H{
"message": "demo",
})
})
// 监听8080 端口
r.Run(":8080")
}
Main 函数中,咱们能够看到,开启了一个 web 服务,监听的端口是 8080,其间运用 Use 方法相关了 2 个中间件,分别是 Demo2 和 Demo1
Gin 结构中,先新建一个引擎,然后经过 Use 方法来将中间件和路由相关起来,这些中间件会关于每一个恳求形成一个调用链
此处的调用链便是经过 Use 方法中运用 append 来进行追加的
// Use adds middleware to the group, see example code in GitHub.
func (group *RouterGroup) Use(middleware ...HandlerFunc) IRoutes {
group.Handlers = append(group.Handlers, middleware...)
return group.returnObj()
}
因而,关于咱们自定义的中间件,先相关的中间件就先履行,后相关的中间件就后履行,这里咱们简略写了两个自定义中间件
中间件,实践上便是去写一个这样的函数
// HandlerFunc defines the handler used by gin middleware as return value.
type HandlerFunc func(*Context)
关于 Demo1 自定义中间件实现是这样的
- 代码在 c.Next() 前的会在恳求详细接口之前进行运转
- 在代码 c.Next() 后的代码会在履行完详细接口之后履行
能够看到此处咱们简略的增加了打印,以及记载接口履行的时刻
func Demo1() gin.HandlerFunc {
return func(c *gin.Context) {
// 恳求接口之前
a := time.Now()
log.Println("--before--demo1----")
c.Next()
// 恳求接口之后
log.Println("--after--demo1----")
dur := time.Since(a)
log.Println("req Time consuming : ",dur)
}
}
Demo2 也是类似的逻辑,仅仅是增加一些打印
程序运转起来,咱们恳求 localhost:8080/test
接口,即可检查到咱们的打印信息如下
仔细的朋友能够看出来,此处的中间件的履行次序很明显是一个先进后出的作用,没错,此处的中间件的确做法如此
能够看到,履行次序是这样的 Demo2 -> Demo1 -> /test 路由 -> Demo1 -> Demo2
那么关于 Gin 的中间件详细是个啥,怎么运用你也会,是不是中间件不就那么回事呢?
天然,此处仅仅是做一个抛砖引玉,让不知 web 中间件的人知道其详细是何物
假如要深入研究,能够检查 Gin 的源码,仍是十分有意思的,假如有必要,今后能够写一篇关于中心源码深入解读的
哪一些场景能够运用 web 中间件?
- 接口限流场景
Gin 中有现成的限流组件 golang.org/x/time/rate
, 详细关于限流相关的常识能够检查文末相关链接
- 数据打点场景
例如记载接口呼应时长,恳求路由成果,一般这种打点数据数据会写到日志中,别的系统中有别的一个应用会来扫日志里边的记载,最终推到详细做日志剖析和聚合的组件上
例如相关的组件就有 prometheus ,grafana 等等
- 接口认证场景
例如 web 结构中需求做鉴权,例如接口需求校验 token 才干进入到详细的路由去做实践的事务,就能够把鉴权放到中间件中进行处理
- 链路盯梢
对每一个恳求都去带上 span ,实践上都是放到 ctx 来做文章,便于排查问题时,直接就能够看到整条链路中哪个节点呈现了问题
- 数据压缩,数据预处理等等,欢迎 xdm 进行弥补哦
感谢阅览,欢迎交流,点个赞,重视一波 再走吧
欢迎点赞,重视,保藏
朋友们,你的支持和鼓舞,是我坚持共享,进步质量的动力
技能是敞开的,咱们的心态,更应是敞开的。拥抱变化,向阳而生,努力向前行。
我是阿兵云原生,欢迎点赞重视保藏,下次见~
文中说到的技能点,感兴趣的能够检查这些文章:
- 简略理解微服务限流、降级、熔断
- 最常用的限流算法以及怎么在http中间件中加入流控
- 共享一波gin的路由算法
- Gin实战演练
- 瞧一瞧 gRPC的拦截器