基础中间件
func logging(f http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
log.Println(r.URL.Path)
f(w, r)
}
}
func foo(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "foo")
}
func bar(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "bar")
}
logging方法中,请求执行方法嵌套了请求执行方法。外层的请求执行方法用于打印日志,里面的请求执行方法用于处理http请求。
foo方法和bar方法分别是具体的请求执行方法。
http.HandleFunc("/foo", logging(foo))
http.HandleFunc("/bar", logging(bar))
http.ListenAndServe(":8090", nil)
以上代码,将请求执行方法和url路径关联,并监听指定端口号。
以下是完整代码:
package main
import (
"fmt"
"log"
"net/http"
)
func logging(f http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
log.Println(r.URL.Path)
f(w, r)
}
}
func foo(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "foo")
}
func bar(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "bar")
}
func main() {
http.HandleFunc("/foo", logging(foo))
http.HandleFunc("/bar", logging(bar))
http.ListenAndServe(":8090", nil)
}
进阶中间件
type Middleware func(http.HandlerFunc) http.HandlerFunc
func Chain(f http.HandlerFunc, middlewares ...Middleware) http.HandlerFunc {
for _, m := range middlewares {
f = m(f)
}
return f
}
Middleware是中间件的类型,该类型是一个方法,参数是请求响应方法,返回的也是请求响应方法。
Chain方法的功能是包装请求响应方法,也就是在参数f这个请求响应方法的外层逐层包装中间件。
func Logging() Middleware {
return func(f http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
defer func() { log.Println(r.URL.Path, time.Since(start)) }()
f(w, r)
}
}
}
func Method(m string) Middleware {
return func(f http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
if r.Method != m {
http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
return
}
f(w, r)
}
}
}
以上代码会包装请求响应方法,扩展其功能。
以下是完整代码:
package main
import (
"fmt"
"log"
"net/http"
"time"
)
type Middleware func(http.HandlerFunc) http.HandlerFunc
func Logging() Middleware {
return func(f http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
defer func() { log.Println(r.URL.Path, time.Since(start)) }()
f(w, r)
}
}
}
func Method(m string) Middleware {
return func(f http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
if r.Method != m {
http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
return
}
f(w, r)
}
}
}
func Chain(f http.HandlerFunc, middlewares ...Middleware) http.HandlerFunc {
for _, m := range middlewares {
f = m(f)
}
return f
}
func Hello(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "hello world")
}
func main() {
http.HandleFunc("/", Chain(Hello, Method("GET"), Logging()))
http.ListenAndServe(":8090", nil)
}
以上代码有个问题,当中间件过多时,http.HandlerFunc会嵌套很多层。
完善中间件
type Middleware func(http.ResponseWriter, *http.Request) bool
func Chain(f http.HandlerFunc, middlewares ...Middleware) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
for _, m := range middlewares {
if !m(w, r) {
return
}
}
f(w, r)
}
}
相比上面的代码,Middleware类型的返回值不再是http.HandlerFunc,而是bool。
func Logging() Middleware {
return func(w http.ResponseWriter, r *http.Request) bool {
start := time.Now()
defer func() { log.Println(r.URL.Path, time.Since(start)) }()
return true
}
}
func Method(m string) Middleware {
return func(w http.ResponseWriter, r *http.Request) bool {
if r.Method != m {
http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
return false
}
return true
}
}
中间件的功能也做了改动。相比之前的代码,现在中间件更专注于自身应有的功能,并在满足条件时返回true,表示可执行下一步;否则,需要中断执行。
以下是完整代码:
package main
import (
"fmt"
"log"
"net/http"
"time"
)
type Middleware func(http.ResponseWriter, *http.Request) bool
func Logging() Middleware {
return func(w http.ResponseWriter, r *http.Request) bool {
start := time.Now()
defer func() { log.Println(r.URL.Path, time.Since(start)) }()
return true
}
}
func Method(m string) Middleware {
return func(w http.ResponseWriter, r *http.Request) bool {
if r.Method != m {
http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
return false
}
return true
}
}
func Chain(f http.HandlerFunc, middlewares ...Middleware) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
for _, m := range middlewares {
if !m(w, r) {
return
}
}
f(w, r)
}
}
func Hello(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "hello world")
}
func main() {
http.HandleFunc("/", Chain(Hello, Method("GET"), Logging()))
http.ListenAndServe(":8090", nil)
}