中间件是什么

开发者在处理请求的过程中,加入用户自己的钩子(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中间件实现

执行顺序

  1. 执行client middlewarenext之前的
  2. 通过网络调用server
  3. 执行server middlewarenext之前的
  4. 执行server middlewarenext之后的
  5. 通过网络返回结果
  6. 执行client middlewarenext之后的

传递方式

  1. 中间件函数之间用context.Context传递
  2. server端和client端之间用http协议请求头传递(grpc中的metadata)