中间件应用模式 #
中间件(Middleware)这个词的含义可大可小。在 Go Web 编程中,“中间件”常常指的是一个实现了 http.Handler 接口的 http.HandlerFunc 类型实例。实质上,这里的中间件就是包装模式和适配器模式结合的产物。
我们来看一个例子:
func validateAuth(s string) error {
if s != "123456" {
return fmt.Errorf("%s", "bad auth token")
}
return nil
}
func greetings(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Welcome!")
}
func logHandler(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
t := time.Now()
log.Printf("[%s] %q %v\n", r.Method, r.URL.String(), t)
h.ServeHTTP(w, r)
})
}
func authHandler(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
err := validateAuth(r.Header.Get("auth"))
if err != nil {
http.Error(w, "bad auth param", http.StatusUnauthorized)
return
}
h.ServeHTTP(w, r)
})
}
func main() {
http.ListenAndServe(":8080", logHandler(authHandler(http.HandlerFunc(greetings))))
}
所谓中间件(如:logHandler、authHandler)本质就是一个包装函数(支持链式调用),但它的内部利用了适配器函数类型(http.HandlerFunc),将一个普通函数(比如例子中的几个匿名函数)转型为实现了 http.Handler 的类型的实例。
运行这个示例,并用 curl 工具命令对其进行测试,我们可以得到下面结果:
$curl http://localhost:8080
bad auth param
$curl -H "auth:123456" localhost:8080/
Welcome!
从测试结果上看,中间件 authHandler 起到了对 HTTP 请求进行鉴权的作用。