Go 每日一库之 negroni
简介
negroni是一个专注于 HTTP 中间件的库 。 它小巧 , 无侵入 , 鼓励使用标准库net/http的处理器(Handler) 。 本文就来介绍一下这个库 。
为什么要使用中间件?有一些逻辑代码 , 如统计、日志、调试等 , 每一个处理器中都需要 , 如果一个个去添加太繁琐了、容易出错、容易遗漏 。 如果我们要统计处理器耗时 , 可以在每个处理器中添加代码统计耗时:
package mainimport ("fmt""net/http""time")func index(w http.ResponseWriter, r *http.Request) {start := time.Now()fmt.Fprintf(w, "home page")fmt.Printf("index elasped:%fs", time.Since(start).Seconds())}func greeting(w http.ResponseWriter, r *http.Request) {start := time.Now()name := r.FormValue("name")if name == "" {name = "world"}fmt.Fprintf(w, "hello %s", name)fmt.Printf("greeting elasped:%fs\n", time.Since(start).Seconds())}func main() {mux := http.NewServeMux()mux.HandleFunc("/", index)mux.HandleFunc("/greeting", greeting)http.ListenAndServe(":8000", mux)}但是这个做法非常不灵活:
- 每增加一个处理器 , 都需要添加这部分代码 。 而这些代码与实际的处理器逻辑并没有什么关系 。 编写处理器时比较容易遗忘 , 特别是要考虑所有的返回路径 。 增加了编码负担;
- 不利于修改:如果统计代码有错误或者需要调整 , 必须要改动所有的处理器;
- 添加麻烦:要添加其他的统计逻辑也需要改动所有的处理器代码 。
func elasped(h func(w http.ResponseWriter, r *http.Request)) http.HandlerFunc {return func(w http.ResponseWriter, r *http.Request) {path := r.URL.Pathstart := time.Now()h(w, r)fmt.Printf("path:%s elasped:%fs\n", path, time.Since(start).Seconds())}}func index(w http.ResponseWriter, r *http.Request) {fmt.Fprintf(w, "home page")}func greeting(w http.ResponseWriter, r *http.Request) {name := r.FormValue("name")if name == "" {name = "world"}fmt.Fprintf(w, "hello %s", name)}func main() {mux := http.NewServeMux()mux.HandleFunc("/", elasped(index))mux.HandleFunc("/greeting", elasped(greeting))http.ListenAndServe(":8000", mux)}我们将额外的与处理器无关的代码放在另外的函数中 。 注册处理器函数时 , 我们不直接使用原始的处理器函数 , 而是用elasped函数封装一层 。 实际上elasped这样的函数就是中间件 。 它封装原始的处理器函数 , 返回一个新的处理器函数 。 从而能很方便在实际的处理逻辑前后插入代码 , 便于添加、修改和维护 。快速使用【Go 每日一库之 negroni】先安装:
$ go get github.com/urfave/negroni后使用:package mainimport ("fmt""net/http""github.com/urfave/negroni")func main() {mux := http.NewServeMux()mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {fmt.Fprintf(w, "Hello World!")})n := negroni.Classic()n.UseHandler(mux)http.ListenAndServe(":3000", n)}negroni的使用非常简单 , 它可以很方便的与http.Handler一起使用 。 negroni.Classic()提供了几个常用的中间件:- negroni.Recovery:恢复panic , 处理器代码中有panic会被这个中间件捕获 , 程序不会退出;
- negroni.Logger:日志 , 记录请求和响应的基本信息;
- negroni.Static:在public目录提供静态文件服务 。
$ go run main.go[negroni] 2020-06-22T06:48:53+08:00 | 200 |20.9966ms | localhost:3000 | GET /[negroni] 2020-06-22T06:48:54+08:00 | 200 |0s | localhost:3000 | GET /favicon.iconegroni.Handler接口negroni.Handler让我们对中间件的执行流程有更灵活的控制:type Handler interface {ServeHTTP(w http.ResponseWriter, r *http.Request, next http.HandlerFunc)}我们编写的中间件签名必须是func(http.ResponseWriter,*http.Request,http.HandlerFunc) , 或者实现negroni.Handler接口:func RandomMiddleware(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {if rand.Int31n(100) <= 50 {fmt.Fprintf(w, "hello from RandomMiddleware")} else {next(w, r)}}func main() {mux := http.NewServeMux()mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {fmt.Fprintf(w, "Hello World!")})n := negroni.New()n.Use(negroni.HandlerFunc(RandomMiddleware))n.UseHandler(mux)http.ListenAndServe(":3000", n)}上面代码中实现了一个随机的中间件 , 有一半的概率直接从RandomMiddleware这个中间件返回 , 一半的概率执行实际的处理器函数 。 运行程序 , 在浏览器中不停地刷新页面localhost:3000看看效果 。注意 , 实际上func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc)只是一个方便的写法 。 在调用n.Use时使用了negroni.HandlerFunc做了一层封装 , 而negroni.HandlerFunc实现了negroni.Handler接口:
- 纠结|硬杠红米Note9Pro?iQOO Z1跌至1575,对比之后纠结了!
- 王兴称美团优选目前重点是建设核心能力;苏宁旗下云网万店融资60亿元;阿里小米拟增资居然之家|8点1氪 | 美团
- 长安|长安傍上华为这个大腿,市值暴涨500亿!可见华为影响力之大?
- 巅峰|realme巅峰之作:120Hz+陶瓷机身+5000mAh 做到了颜值与性能并存
- 蛋壳公寓|官媒发声:绝不能让“割韭菜者”一跑了之!
- 看过明年的iPhone之后,现在下手的都哭了
- 直播销售员|石家庄桥西区插上“互联网+”智慧发展之翼
- 精英|业务流程图怎么绘制?销售精英的经验之谈
- 砍单|iPhone12之后,拼多多又将iPhone12Pro拉下水
- 报名啦!宿迁开展第五届“十大科技之星”评选
