简介
negroni
是一个专注于 HTTP 中间件的库。它小巧,无侵入,鼓励使用标准库net/http
的处理器(Handler
)。本文就来介绍一下这个库。
为什么要使用中间件?有一些逻辑代码,如统计、日志、调试等,每一个处理器中都需要,如果一个个去添加太繁琐了、容易出错、容易遗漏。如果我们要统计处理器耗时,可以在每个处理器中添加代码统计耗时:
package main
import (
"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)
}
但是这个做法非常不灵活:
- 每增加一个处理器,都需要添加这部分代码。而这些代码与实际的处理器逻辑并没有什么关系。编写处理器时比较容易遗忘,特别是要考虑所有的返回路径。增加了编码负担;
- 不利于修改:如果统计代码有错误或者需要调整,必须要改动所有的处理器;
- 添加麻烦:要添加其他的统计逻辑也需要改动所有的处理器代码。
利用 Go 语言的闭包,我们可以将实际的处理器代码封装到一个函数中,在这个函数中执行额外的逻辑:
func elasped(h func(w http.ResponseWriter, r *http.Request)) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
path := r.URL.Path
start := 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 get github.com/urfave/negroni
后使用:
package main
import (
"fmt"
"net/http"
"github.com/urfave/negroni"
)
func main() {
mux := http.NewServeMux()
mux.