如何在Golang中实现中间件-Part 1
当使用net/http
包实现服务的时候,一般使用的是如下的两中处理方式:
- http.HandleFunc
- http.Handle
http.HandleFunc
分析
当使用这种方式的时候,其接受两个参数,一个是字符串格式的匹配符(pattern),另外一个就是func(ResponWrite, *Request)
,
因此只要我们的中间件中返回该类型,那么中间件就是可以实现的
func main(){
http.HandleFunc("/", Hello)
http.ListenAndServe(":8080", nil)
}
func Hello(w http.ResponseWriter, r *http.Request) {
fmt.Print("hello")
}
hello
这个结果,说明我们的写法是没有问题的
实现
接下来,我们需要定义我们的中间件,它需要接收一个` http.HandlerFunc`类型,并且返回一个http.HandlerFunc
这样才能被使用
func MyMiddleware(next http.HandlerFunc)http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
fmt.Println("middleware")
//doSomethinds
next.ServeHTTP(w,r)
}
}
next.ServeHTTP(w, r)
等效于调用next(w, r)
,处理完后会返回响应w
,最终相应会传递到最外层的匿名函数,从而最终会返回到客户端
http.Handle
分析
http.Handle
接受两个参数,一个是匹配符,另外一个是http.Handler
,当我们查看源码的时候,发现其是一个接口类型
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
解决
type MyResponse struct {
next http.Handle
Code int64
Msg string
Errors []string
Data map[string]interface{}
}
func (res *MyResponse)ServeHTTP(w http.ResponseWriter, r *http.Request) {
result, err := json.Marshal(res)
if err 大专栏 Golang Middleware Part 1 · To Be A Better Mancolor:#f92672">!= nil {
fmt.Println(err.Error())
}
w.Write(result)
}
紧接着我们定义两个处理函数
func Hello(w http.ResponseWriter, r *http.Request) {
fmt.Println("hello")
}
func World(w http.ResponseWriter, r *http.Request) {
fmt.Println("world")
}
然后在主函数里面进行调用
var res = new(MyResponse)
res.next = Hello
http.Handle("/hello", res)
res.next = World
http.Handle("/world", res)
http.ListenAndServe(":8080", nil)
world
,这是因为Golang是一门静态的预编译语言,编译完成后,`res`总的next属性
将会永远指向World
的地址,
因此我们可以做一个映射,将next变成map类型,但是想一想,如果路由非常多的话,那将是一件多可怕的事情,因此我们需要另辟蹊径,有没有其他的办法可以实现,查看源码我们可以发现
之前我们所使用过的http.HandleFunc
与之相对应的还有一个类型http.HandlerFunc
,该类型实现了ServerHTTP
方式
type HandlerFunc func(ResponseWriter, *Request)
// ServeHTTP calls f(w, r).
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
f(w, r)
}
func MySencondMiddleware(next http.HandlerFunc) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
//do somethings
next.ServeHTTP(w, r)
})
}