golang http 中间件

源码链接

golang的http中间件的实现 首先实现一个http的handler接口

type Handler interface {
    ServeHTTP(ResponseWriter, *Request)
}

type Router struct {
    route map[string]Handle
}

func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
}

通过函数包裹的方式实现

中间件v1.0

1.通过匿名函数 将handler包裹起来 然后再 调用传进来的handler。在执行传进来的参数之前
就可以做到记录日志 等一些中间件的功能

2.如果有多个中间件 那么就多个函数 一层一层包裹

func withMiddle(h Handle) Handle {
    return func(writer http.ResponseWriter, request *http.Request) {
        t := time.Now()
        defer func() {
            log.Println("time spend is ", time.Since(t))
        }()
        h(writer, request)
    }
}

func (r *Router) Register1(route string, f Handle) {
    r.route[route] = withMiddle(f)
}

func (r *Router) Register2(route string, f Handle) {
    r.route[route] = withMiddLog(withMiddTime(f))
}

Register("/bench", func(writer http.ResponseWriter, request *http.Request) {
    time.Sleep(time.Second)
    fmt.Println("bench sleep 1 second")
})

中间件v1.1

注册的时候 可以更加简化一些 通过匿名函数的方式 当然这种方式没有传递参数
只是作为演示用的

func (r *Router) Register(route string, f HandlerFunc) {
    r.route[route] = withMiddLog(withMiddTime(func(writer http.ResponseWriter, request *http.Request) {
        f()
    }))
}

中间件v2.0

针对中间件v1.1中的没法传递 http中的读写参数的问题 可以封装一个context
将http的读写参数都包裹进来 这样就可以很方便的处理读写了

func (r *Server) Register(route string, f HandlerFunc) {
    r.route[route] = withMiddLog(withMiddTime(func(writer http.ResponseWriter, request *http.Request) {
        f(r.createContext(writer, request))
    }))
}
r.Register("/bench", func(c *Context) {
        time.Sleep(time.Second)
        fmt.Println("bench sleep 1 second")
        c.Writer.Write([]byte("hello!\r\n"))
    })

golang框架gin中的实现

中间件v3.0

核心理念是将中间件和最后的函数 一视同仁 。通过一个for循环遍历具体的可以参考代码

func (c *Context) Next() {
    c.index++
    //for中的index++是为了退出循环 否则没法退出
    for ; c.index < len(c.middle); c.index++ {
        c.middle[c.index](c)
    }
}

func withMiddTime() HandleContext {
    return func(c *Context) {
        t := time.Now()
        defer func() {
            fmt.Println("withMiddTime end time", time.Since(t))
        }()
        fmt.Println("withMiddTime start ", time.Since(t))
        c.Next()
    }
}
func (s *Server) Register(path string, f ...HandleContext) {
    handleNew := make([]HandleContext, 0, len(s.handle)+len(f))
    handleNew = append(handleNew, s.handle...)
    handleNew = append(handleNew, f...)
    s.routeHandler(path, func(writer http.ResponseWriter, request *http.Request) {
        s.createContext(writer, request, handleNew).Next()
    })
}

最新文章

  1. Idea中包内中的置文件如何发布到编译后的目录中去
  2. 制作stick侧边栏导航效果
  3. iOS中多线程原理与runloop介绍
  4. Handler(消息机制)
  5. 字符串匹配算法之SimHash算法
  6. 有关于CSS的面试题和练习
  7. Eddy&#39;s mistakes(字母大小写转换)strlwr函数的应用
  8. pwnable.kr-fd-Writeup
  9. umask的作用
  10. centos6/7通用查看系统版本
  11. 使用angular4和asp.net core 2 web api做个练习项目(二), 这部分都是angular
  12. mysql 从一个表中查数据,插入另一个表
  13. Python调用ansible API系列(三)带有callback的执行adhoc和playbook
  14. 解决 VS2017 打断点无效
  15. Nginx详解十七:Nginx深度学习篇之动静分离
  16. python爬取今日头条关键字图集
  17. GBK-----UTF-8编码格式问题浅析
  18. [NOIp2009普及组]细胞分裂
  19. pthread_detach
  20. 快速搭建Spring Boot项目

热门文章

  1. 51nod 1515 明辨是非 并查集+set维护相等与不等关系
  2. 蓝桥校内选拔赛B题(不一定正确)
  3. SpringBoot---Web开发---SSL配置
  4. js得到当前页面的url信息
  5. nodejs 实践:express 最佳实践(六) express 自省获得所有的路由
  6. SQL2000,2005,2008安装在一台机子上
  7. JDK8下的HashMap有什么特别之处?
  8. 读写属性/if判断那点事/数组
  9. sqlserver 查询某表的所有列名
  10. HDU 5501 The Highest Mark (贪心+DP,经典)