zoukankan      html  css  js  c++  java
  • golang中间件的实现

    中间件是什么

    开发者在处理请求的过程中,加入用户自己的钩子(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 middleware next之前的
    2. 通过网络调用server
    3. 执行server middleware next之前的
    4. 执行server middleware next之后的
    5. 通过网络返回结果
    6. 执行client middleware next之后的

    传递方式

    1. 中间件函数之间用context.Context传递
    2. server端和client端之间用http协议请求头传递(grpc中的metadata)
  • 相关阅读:
    JAVA基础知识之多线程——线程通信
    为Apache配置虚拟机Virtual Host
    SignalR的坑爹细节
    ashx入侵
    aspnet5安装ef7备忘
    aspnet5备忘
    NHibernate初步使用
    MVC中发生System.Data.Entity.Validation.DbEntityValidationException验证异常的解决方法
    关于NLog的target和Layout
    泛型约束的大概模样
  • 原文地址:https://www.cnblogs.com/zhaohaiyu/p/11578490.html
Copyright © 2011-2022 走看看