关注我,了解更多源码设计及实现细节...

echo 框架中的 middleware 设计深度解析

“ echo web 框架是 go 语言开发的一种高性能,可扩展,轻量级的web框架。几行代码就可以启动一个高性能的 http 服务端... ”

Echo 简介

了解 Go 语言的同学可能熟悉 Echo ,它是一款高性能、极简的 Web 框架。

Package echo implements high performance, minimalist Go web framework.

Echo 从性能和功能的角度都极大的提升了开发效率。相比其他的 Web 框架,它提供 “ 支持更多类型以及效率更高的 Router,Middleware、及高效的内存管理……“ 等众多优秀的功能特性,并赢得了众多开发者的青睐。

这里就其中 Middleware 组件良好的设计实现展开介绍。

Middleware 组件介绍

Middleware,嵌入在 HTTP 的请求和响应之间。它可以获得 Echo#Context 对象用来进行一些特殊的操作,比如记录每个请求或者统计请求数。

根据其作用生效的位置及对象,可将 Middleware 分为四种,分别是:Before router、After router、Group、Router 

Before router

Echo#Pre() 用于注册一个在路由执行之前运行的中间件,可以用来修改请求的一些属性。比如在请求路径结尾添加或者删除一个’/‘来使之能与路由匹配。

下面的这几个内建中间件应该被注册在这一级别:

  • AddTrailingSlash

  • RemoveTrailingSlash

  • MethodOverride

    注意: 由于在这个级别路由还没有执行,所以这个级别的中间件不能调用任何 echo.Context 的 API。

After router

这个级别的中间件运行在路由处理完请求之后,可以调用所有的 echo.Context API。

下面的这几个内建中间件应该被注册在这一级别:

  • BodyLimit

  • Logger

  • Gzip

  • Recover

  • BasicAuth

  • JWTAuth

  • Secure

  • CORS

  • Static

Group

当在路由中创建一个组的时候,可以为这个组注册一个中间件。例如,给 admin 这个组注册一个 BasicAuth 中间件。

e := echo.New()admin := e.Group("/admin", middleware.BasicAuth())

也可以在创建组之后用 admin.Use()注册该中间件。

Route 

当你创建了一个新的路由,可以选择性的给这个路由注册一个中间件。

e := echo.New()e.GET("/", <Handler>, <Middleware...>)

Middleware 的实现

// MiddlewareFunc defines a function to process middleware.MiddlewareFunc func(HandlerFunc) HandlerFunc// HandlerFunc defines a function to server HTTP requests.HandlerFunc func(Context) error

可以看到 middleware 类型是一个匿名函数,参数和返回值的类型一样,都是 HandlerFunc 类型。

HandlerFunc 类型,是 echo 框架处理业务逻辑的 Handler 结构,如下:

e.GET("/v1/test/metrics", func(c echo.Context) error {     return hs.apiQueryMetrics(c)})

这样的设计,是偶然吗?

其实不是,我们已 middleware.Gzip() 为例:

e.Use(middleware.Gzip())

Use 的实现是,将 Gzip() 加入 echo 的 middleware 数组:

// Use adds middleware to the chain which is run after router.func (e *Echo) Use(middleware ...MiddlewareFunc) {e.middleware = append(e.middleware, middleware...)}

middleware.Gzip() 的参数是 next echo.HandlerFunc 下一个 middleware 的 返回值:

// GzipWithConfig return Gzip middleware with config.// See: `Gzip()`.func GzipWithConfig(config GzipConfig) echo.MiddlewareFunc {// Defaultsif config.Skipper == nil {  config.Skipper = DefaultGzipConfig.Skipper}if config.Level == 0 {  config.Level = DefaultGzipConfig.Level}return func(next echo.HandlerFunc) echo.HandlerFunc {  return func(c echo.Context) error {   if config.Skipper(c) {    return next(c)   }   res := c.Response()   res.Header().Add(echo.HeaderVary, echo.HeaderAcceptEncoding)   if strings.Contains(c.Request().Header.Get(echo.HeaderAcceptEncoding), gzipScheme) {    res.Header().Add(echo.HeaderContentEncoding, gzipScheme) // Issue #806    rw := res.Writer    w, err := gzip.NewWriterLevel(rw, config.Level)    if err != nil {     return err    }    defer func() {     if res.Size == 0 {      if res.Header().Get(echo.HeaderContentEncoding) == gzipScheme {       res.Header().Del(echo.HeaderContentEncoding)      }      // We have to reset response to it's pristine state when      // nothing is written to body or error is returned.      // See issue #424, #407.      res.Writer = rw      w.Reset(ioutil.Discard)     }     w.Close()    }()    grw := &gzipResponseWriter{Writer: w, ResponseWriter: rw}    res.Writer = grw   }   return next(c)  }}}

我们了解 Use()、Gzip() 之后,在来看一下 middleware 的执行部分:

func (e *Echo) add(method, path string, handler HandlerFunc, middleware ...MiddlewareFunc) {name := handlerName(handler)e.router.Add(method, path, func(c Context) error {  h := handler  // Chain middleware  for i := len(middleware) - 1; i >= 0; i-- {   h = middleware[i](h)  }  return h(c)})r := &Route{  Method:  method,  Path:    path,  Handler: name,}e.router.routes[method+path] = r}

关注其中的 for 循环,通过循环,倒序将 middleware 数组中的 MiddlewareFunc 合并成一个 echo.HandlerFunc 去执行。在执行过程中,按照循环的倒序去依次执行 middlewareFunc 定义的函数。

这种设计类似算法中的 递归思想,通过定义 参数和返回相同类型的约束,使函数可以完成递归的实现;并将函数类型与 echo 框架的处理 handler 耦合,这样完美的实现了 handler 的前后代理,在设计模式上,这种设计被称为 代理模式。

echo 的实现包含大量的优秀源码及设计思路,是一个指导个人成长的优秀教材。

关注我,了解更多源码设计及实现细节...

推荐阅读:

|百度信息流和搜索双引擎业务中的 KV 存储实践...



#架构|高可用|高性能|高并发|高容错|HTTP|TLS|网络|加密算法|面试|同步|异步#

echo 框架中的 middleware 设计深度解析相关推荐

  1. DDD领域驱动设计深度解析

    目录 DDD领域驱动设计深度解析 DDD凝聚了软件工程的智慧 DDD领域驱动设计的历史 什么是领域 Domain 领域驱动设计 领域驱动设计几大原则详解 领域驱动模型的概念 领域驱动设计的挑战 DDD ...

  2. Go实战--golang中使用echo框架中JSONP(labstack/echo)

    生命不止,继续 go go go !!! 继续,echo web框架,今天就聊一聊JSONP. JSONP 1.什么是JSONP? JSONP (JSON with padding) is used ...

  3. cmstop框架中的js设计content.js

    控制cmstop框架中action的js 内容模块 找出当前页面的js的思路 01先找显示页面的当前文件.在页面文件中-->找(编辑,删除)按钮-->找获取这个按钮的js选择器 02看加载 ...

  4. 游戏中的颜色:深度解析游戏设计工具

    有关颜色的知识横跨好几个学科,比如物理学.生物学.心理学.艺术和设计.对于美术师们来说,颜色是创造感情非常有用的工具,对于游戏设计师们来说,它是强调功能最有用的方式,对于营销者们来说,可以用颜色对产品 ...

  5. Java集合框架中隐藏的设计套路

    我们的世界不应该只有"胡萝卜" 进入正题之前容我先扯点别的. 最近突然想到了一个驴子和胡萝卜不得不说的故事.说是一个人坐在驴子背上,用一根长杆绑着一根胡萝卜,然后把胡萝卜悬到驴子的 ...

  6. 框架中的高大上设计为了啥?

    源码中经常看到调用本类中的抽象方法,运行时才知道是哪个实现类.但是我们看源码时不知道是哪个实现类,需要debug进行查看到是哪个实现类!!!! 源码中为啥会用好多设计模式如:模板,委派,装饰者,责任链 ...

  7. Go实战--golang中使用echo框架中的HTTP/2、Server Push(labstack/echo、golang.org/x/net/http2)

    生命不止,继续 go go go !!! 继续echo web框架,今天搞一下http2. HTTP2 What is HTTP/2? HTTP/2 is a replacement for how ...

  8. python中scrapy的middleware是干嘛的_Python之爬虫(十九) Scrapy框架中Download Middleware用法...

    这篇文章中写了常用的下载中间件的用法和例子. Downloader Middleware处理的过程主要在调度器发送requests请求的时候以及网页将response结果返回给spiders的时候,所 ...

  9. OpenCV中waitKey()函数的深度解析

    while (char(waitKey(1)) != 'q') {} 相信不少,都是冲着这句代码来的,是不是无法退出? 注意:鼠标必须激活当前窗口, 即鼠标要点一下窗口(图像),不然要是放在cmd窗口 ...

最新文章

  1. Eclipse编辑jsp、js文件时,经常出现卡死现象解决汇总
  2. Codeforces Gym 100187M M. Heaviside Function two pointer
  3. VS2019正确创建C++步骤以及扩展插件美化你的VS2019的IDE开发环境
  4. VUEJS-checkbox全选全不选
  5. 程序员成熟的标志《程序员成长路线图:从入门到优秀》
  6. pgsql中float4导致java程序精度丢失_Java基础系列02
  7. 09-03-06 FreeEIM 姗姗来迟
  8. 21南阳理工oj新生赛Round#5--这是一道二分题
  9. 【嵌入式Linux】嵌入式Linux驱动开发基础知识之第一个驱动
  10. 剑指offer之使数组的奇数在偶数前面
  11. 《Java并发编程的艺术》第3章 Java内存模型
  12. 什么是ERPS?ERPS有什么作用?
  13. 代码覆盖率分析 - VectorCAST/CBA
  14. springboot+vue线上教学平台(源码+文档)
  15. matlab汽车驱动力与行驶阻力,用matlab绘制汽车驱动力 行驶阻力平衡图
  16. 平台网络安全能力知多少
  17. knockout学习笔记
  18. android 授予root权限,关于android手机获得ROOT权限问题
  19. 快加入「我的最爱」吧 Python 开发者不容错过的30 个Github 开源专案(下)
  20. wd移动硬盘测试软件,让你的秘密高枕无忧 WD My Passport随行版移动硬盘评测

热门文章

  1. MobileNeXt:Rethinking Bottleneck Structure for Efficient Mobile Network Design
  2. 2022考研复试时间轴及注意事项!重要哟!
  3. 8位单片机(51 STC8)C语言处理32位unsigned long型数据之计算出错
  4. 大数据非万能 却是商业定海神针
  5. dotnet发布运行
  6. 中秋节快乐,给大家准备了用Python和c++的感谢与祝福代码!(有一些是借鉴的)
  7. 移动硬盘上的linux系统安装软件下载,UNetbootin Linux
  8. java 接收 xml_关于java后台如何接收xml格式的数据
  9. 父与子的编程游戏——滑雪者游戏
  10. Ajax与Axios的区别