其实grpc的中间件和编写http的中间件一样
http服务
处理器:Handler
定义
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
http服务,最重要的就是处理器:Handler ,一个接口
我们需要定义一个处理器,实现ServeHTTP方法用来响应HTTP请求
下面是对处理器:Handler 的介绍
ServeHTTP应该将响应头和数据写入ResponseWriter,然后返回。
Returning signals代表请求结束,在完成ServeHTTP调用的时候或之后,不允许使用ResponseWriter ,也不允许从 Request.Body读取信息
根据HTTP客户端软件、HTTP协议版本以及客户端和Go服务器之间的任何中介,在ResponseWriter写入之后可能无法从Request.Body读取数据。
谨慎的处理程序应该首先读取Request.Body,然后回复。
除了读取Body之外,处理程序不应该修改提供的请求。
如果ServeHTTP panics,服务器(ServeHTTP的调用者)假设恐慌的影响与active request隔离。
它恢复恐慌,将堆栈跟踪记录到服务器错误日志,并根据HTTP协议关闭网络连接或发送HTTP/2 RST_STREAM。
然后中止处理程序,以便客户端看到中断的响应,服务器不记录错误,而是使用ErrAbortHandler值去panic。
对指定url添加中间件
我们先定义一个类型:myHandler1,并实现ServeHTTP 方法来实现Handler 接口
type myHandler1 struct{}
func (my *myHandler1) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello myHandler1 ")
}
然后直接访问127.0.0.1:8888/h1 就可以返回Hello myHandler1
这是最简单的服务。
这里我们想给该服务价格中间件用来做全局log记录或者验证
因为myh实现了Handler接口,name就可以直接传递进来
func middleware1(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// http.Error(w, http.StatusText(403), 403)
tStart := time.Now()
next.ServeHTTP(w, r)
tEnd := time.Since(tStart)
fmt.Println("middleware1:", tEnd)
})
}
mux.Handle("/h1", &myh)
改成
mux.Handle("/h2", middleware1(&myh))
简单实现一个服务
package main
import (
"fmt"
"net/http"
"time"
)
type myHandler1 struct{}
func (my *myHandler1) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello myHandler1 ")
}
func middleware1(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// http.Error(w, http.StatusText(403), 403)
tStart := time.Now()
next.ServeHTTP(w, r)
tEnd := time.Since(tStart)
fmt.Println("middleware1:", tEnd)
})
}
func main() {
mux := http.NewServeMux()
myh := &myHandler1{}
mux.Handle("/h1", middleware1(myh))
if err := http.ListenAndServe(":8888", mux); err != nil {
panic(err)
}
}
对路由器添加中间件
上面是对单个url的验证,因为mux 也实现了ServeHTTP方法,所以middleware1可以直接对mux使用
func main() {
mux := http.NewServeMux()
myh := &myHandler1{}
mux.Handle("/h1", myh)
if err := http.ListenAndServe(":8888", middleware1(mux)); err != nil {
panic(err)
}
}
换句话说,只要实现了ServeHTTP方法,就可以对该对象使用上面的中间件。。。
对于grpc-gateway
mux := runtime.NewServeMux()
其中mux 就实现了ServeHTTP ,实现了Handler方法,所以按照该方式编写中间件即可
Handler的适配器:HandlerFunc
定义
type HandlerFunc func(ResponseWriter, *Request)
// ServeHTTP calls f(w, r).
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
f(w, r)
}
介绍
HandlerFunc类型是一个适配器,允许使用普通函数作为HTTP处理程序。如果f是具有适当签名的函数,HandlerFunc(f)是调用f的处理程序。
这里提供了个适配器,也就是说,你按照(w http.ResponseWriter, r *http.Request)格式实现一个函数,然后转换成HandlerFunc 类型,因为HandlerFunc 实现了ServeHTTP 方法,方法内部调用了自身,所以免去了去实现Handler 接口的步骤。
这样可以快速实现一个服务。
对此也提供了实现中间件的方式,对指定url加中间件
package main
import (
"fmt"
"net/http"
"time"
)
func hello1(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello 111 ")
}
func middleware2(h http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
tStart := time.Now()
h(w, r) //执行调用
tEnd := time.Since(tStart)
fmt.Println("middleware1:", tEnd)
}
}
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/h2", middleware2( http.HandlerFunc(hello1)))
if err := http.ListenAndServe(":8888", mux); err != nil {
panic(err)
}
}