中间件是什么
开发者在处理请求的过程中,加入用户自己的钩子(Hook)函数。这个钩子函数就叫中间件,中间件适合处理一些公共的业务逻辑,比如登录认证、权限校验、数据分页、记录日志、耗时统计等。
代码实现
package main import ( "context" "fmt" "time" ) // 中间件的函数 type MiddlewareFunc func(ctx context.Context, req interface{}) (resp interface{}, err error) // 构建中间件函数使用 type Middleware func(MiddlewareFunc) MiddlewareFunc type LogFile struct { logName string } // 构建一个中间件函数 func buildMiddleWare(handle MiddlewareFunc) MiddlewareFunc { var chain []Middleware var LogFiler LogFile chain = append(chain,ExeaTime) chain = append(chain,NewPrintLOg(LogFiler)) chain = append(chain,judgeReq) middle := buildChain(chain) return middle(handle) } // 把中间件的数组构建成个链 // 最先执行的在最外层 // next执行下一个 下面的为执行为请求函数handle之后执行 执行顺序和数组顺序相反 func buildChain(chain []Middleware) Middleware { return func(next MiddlewareFunc) MiddlewareFunc { for i := len(chain) - 1; i >= 0; i-- { next = chain[i](next) } return next } } // 执行时间中间件 func ExeaTime(next MiddlewareFunc) MiddlewareFunc { return func(ctx context.Context, req interface{}) (resp interface{}, err error) { fmt.Println("执行时间中间件") startTime := time.Now().UnixNano() resp, err = next(ctx, req) // 执行下一个 if err != nil { fmt.Println("执行函数失败") return } endTime := time.Now().UnixNano() fmt.Println("函数执行时间为:", endTime-startTime) return } } // 打印日志中间件 func NewPrintLOg(LogFiler LogFile) Middleware { return func(next MiddlewareFunc) MiddlewareFunc { return func(ctx context.Context, req interface{}) (resp interface{}, err error) { fmt.Println("打印日志中间件") fmt.Println(LogFiler.logName) resp, err = next(ctx, req) return } } } // 判断req是否为空中间件 func judgeReq(next MiddlewareFunc) MiddlewareFunc { return func(ctx context.Context, req interface{}) (resp interface{}, err error) { fmt.Println("判断req是否为空中间件") if req == "" { fmt.Println("req为空") return } resp, err = next(ctx, req) return } } // 请求函数 func Handle(ctx context.Context, req interface{}) (resp interface{}, err error) { resp = req fmt.Println("Handle") time.Sleep(time.Second) return } func main() { MiddlewareFunction := buildMiddleWare(Handle) // 吧请求函数穿进去 并形成个带中间件的函数 resp,err := MiddlewareFunction(context.TODO(),"zhy") // 执行函数 if err != nil { fmt.Println("main err:",err) return } fmt.Println("main resp:",resp) }
执行结果:
执行时间中间件 打印日志中间件 判断req是否为空中间件 Handle 函数执行时间为: 1001447800 main resp: zhy
执行顺序
gRPC中间件实现
执行顺序
- 执行client middlewarenext之前的
- 通过网络调用server
- 执行server middlewarenext之前的
- 执行server middlewarenext之后的
- 通过网络返回结果
- 执行client middlewarenext之后的
传递方式
- 中间件函数之间用context.Context传递
- server端和client端之间用http协议请求头传递(grpc中的metadata)