V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
qbhy
V2EX  ›  Go 编程语言

🔥 🔥 🔥 新鲜出炉! go 版本的 pipeline 发布啦,你还在愁 go 没有好用的中间件吗?

  •  
  •   qbhy ·
    qbhy · 2022-01-29 10:38:55 +08:00 · 3744 次点击
    这是一个创建于 1027 天前的主题,其中的信息可能已经有所发展或是发生改变。

    Goal-web/pipeline

    goal-web/pipeline
    这是一个管道库,实现了 和 laravel 一样的管道功能,如果你很熟悉 laravel 的管道或者中间件,那你一定对这个库很有亲切感。

    安装 - install

    go get github.com/goal-web/pipeline
    

    使用 - usage

    得益于 goal 强大的容器,你可以在管道(pipe)和目的地(destination)任意注入容器中存在的实例

    对管道不熟悉的同学,可以把 pipe 理解为中间件,destination 就是控制器方法

    package tests
    
    import (
    	"fmt"
    	"github.com/goal-web/container"
    	"github.com/goal-web/contracts"
    	"github.com/goal-web/pipeline"
    	"github.com/pkg/errors"
    	"testing"
    )
    
    type User struct {
    	Id   int
    	Name string
    }
    
    func TestPipeline(t *testing.T) {
    	pipe := pipeline.New(container.New())
    	pipe.Send(User{Id: 1, Name: "goal"}).
    		Through(
    			func(user User, next pipeline.Pipe) interface{} {
    				fmt.Println("中间件 1-start")
    				result := next(user)
    				fmt.Println("中间件 1-end")
    				return result
    			},
    			func(user User, next pipeline.Pipe) interface{} {
    				fmt.Println("中间件 2-start")
    				result := next(user)
    				fmt.Println("中间件 2-end")
    				return result
    			},
    		).
    		Then(func(user User) {
    			fmt.Println("then", user)
    		})
    }
    
    // TestPipelineException 测试异常情况
    func TestPipelineException(t *testing.T) {
    	defer func() {
    		recover()
    	}()
    	pipe := pipeline.New(container.New())
    	pipe.Send(User{Id: 1, Name: "goal"}).
    		Through(
    			func(user User, next pipeline.Pipe) interface{} {
    				fmt.Println("中间件 1-start")
    				result := next(user)
    				fmt.Println("中间件 1-end", result)
    				return result
    			},
    			func(user User, next pipeline.Pipe) interface{} {
    				fmt.Println("中间件 2-start")
    				result := next(user)
    				fmt.Println("中间件 2-end", result)
    				return result
    			},
    		).
    		Then(func(user User) {
    			panic(errors.New("报个错"))
    		})
    }
    
    // TestStaticPipeline 测试调用 magical 函数
    func TestStaticPipeline(t *testing.T) {
    	// 应用启动时就准备好的中间件和控制器函数,在大量并发时用 StaticPipeline 可以提高性能
    	middlewares := []contracts.MagicalFunc{
    		container.NewMagicalFunc(func(user User, next pipeline.Pipe) interface{} {
    			fmt.Println("中间件 1-start")
    			result := next(user)
    			fmt.Println("中间件 1-end", result)
    			return result
    		}),
    		container.NewMagicalFunc(func(user User, next pipeline.Pipe) interface{} {
    			fmt.Println("中间件 2-start")
    			result := next(user)
    			fmt.Println("中间件 2-end", result)
    			return result
    		}),
    	}
    	controller := container.NewMagicalFunc(func(user User) int {
    		fmt.Println("then", user)
    		return user.Id
    	})
    
    	pipe := pipeline.Static(container.New())
    	result := pipe.SendStatic(User{Id: 1, Name: "goal"}).
    		ThroughStatic(middlewares...).
    		ThenStatic(controller)
    
    	fmt.Println("穿梭结果", result)
    	/**
    	中间件 1-start
    	中间件 2-start
    	then {1 goal}
    	中间件 2-end [1]
    	中间件 1-end [1]
    	穿梭结果 [1]
    	 */
    }
    

    在 goal 之外的框架使用 - use in frameworks other than goal

    这个库并不会限制你在哪个框架使用它,所以你可以在任意 go 环境使用这个管道库

    goal-web
    goal-web/pipeline
    [email protected]

    第 1 条附言  ·  2022-01-30 00:13:07 +08:00
    // TestPurePipeline 测试纯净的 pipeline
    func TestPurePipeline(t *testing.T) {
    	// 如果你的应用场景对性能要求极高,不希望反射影响你,那么你可以试试下面这个纯净的管道
    	pipe := pipeline.Pure()
    	result := pipe.SendPure(User{Id: 1, Name: "goal"}).
    		ThroughPure(
    			func(user interface{}, next pipeline.Pipe) interface{} {
    				fmt.Println("中间件1-start")
    				result := next(user)
    				fmt.Println("中间件1-end", result)
    				return result
    			},
    			func(user interface{}, next pipeline.Pipe) interface{} {
    				fmt.Println("中间件2-start")
    				result := next(user)
    				fmt.Println("中间件2-end", result)
    				return result
    			},
    		).
    		ThenPure(func(user interface{}) interface{} {
    			fmt.Println("then", user)
    			return user.(User).Id
    		})
    	fmt.Println("穿梭结果", result)
    	/**
    	中间件1-start
    	中间件2-start
    	then {1 goal}
    	中间件2-end 1
    	中间件1-end 1
    	穿梭结果 1
    	 */
    }
    
    
    16 条回复    2022-02-09 15:52:32 +08:00
    qbhy
        1
    qbhy  
    OP
       2022-01-29 10:40:09 +08:00
    其实也不是那么新鲜了,因为是昨天晚上写好的了,早上起来才发的 V2
    bthulu
        2
    bthulu  
       2022-01-29 11:20:42 +08:00
    中间件是不是就类似 java 里的过滤器, 为什么要叫中间件这个名字呢, 感觉好诡异
    ccppgo
        3
    ccppgo  
       2022-01-29 11:37:16 +08:00
    @bthulu PHP 的概念吧,middleware
    qbhy
        4
    qbhy  
    OP
       2022-01-29 14:09:48 +08:00
    @bthulu 只是名字而已吧哈哈,本质上是一个东西,最多可能实现方式不一样
    liuxu
        5
    liuxu  
       2022-01-29 14:53:52 +08:00 via Android
    @bthulu shell 里叫管道,iptables 叫表 /链,都不是以 java 的标准起的名字
    xz410236056
        6
    xz410236056  
       2022-01-29 14:58:30 +08:00
    @bthulu #2 过滤器是 Filter , 中间件可以 Filter 可以 map ,还可以干别的,你觉得叫什么合适呢
    zoharSoul
        7
    zoharSoul  
       2022-01-29 14:58:33 +08:00
    理解为中间件是什么意思?

    中间件不是指比如 rpc, mq, 配置中心, apm, 链路追踪之类的周边设施吗?
    liuxu
        8
    liuxu  
       2022-01-29 15:12:03 +08:00 via Android
    @zoharSoul 其实没必要这么抠字眼,中间件是个思想,不是具体组件

    可以看看红帽的文档
    https://www.redhat.com/zh/topics/middleware/what-is-middleware

    中间件是为应用提供通用服务和功能的软件。数据管理、应用服务、消息传递、身份验证和 API 管理通常都要通过中间件。
    zoharSoul
        9
    zoharSoul  
       2022-01-29 15:13:59 +08:00
    @liuxu #8 对我也是这么理解的, 所以楼主的这个不是中间件
    liuxu
        10
    liuxu  
       2022-01-29 15:36:00 +08:00 via Android
    @zoharSoul 对的,楼主只是为了没用过 linux 管道的人方便理解,类比了中间件的思想,要是楼主也写过 java ,原话应该会是:

    可以理解成 laravel 的中间件,java 的 filter

    插件名,类名 /结构名写的就是管道 pipeline


    顺便给 phper 提一下,laravel 有中间件,而调用中间件方法和 controller 是框架底层的 Pipeline 类
    bigpigeon
        11
    bigpigeon  
       2022-01-29 17:04:01 +08:00
    和 gin 的 middleware 区别在哪里
    qbhy
        12
    qbhy  
    OP
       2022-01-29 17:58:56 +08:00
    我赞成八楼老哥的,中间件是思想,不是具体的组件。
    qbhy
        13
    qbhy  
    OP
       2022-01-29 18:01:01 +08:00
    @bigpigeon 我这个管道库不是某个框架的中间件,只是洋葱模型的管道的一个实现,只是通常用来实现中间件功能。也就是说,你可以在任何需要用到管道的地方使用他,不局限于 gin 或者 goal 或者其他框架
    qbhy
        14
    qbhy  
    OP
       2022-01-30 00:14:14 +08:00
    最新的版本支持了纯净模式,也就是没有容器的管道,因为没有反射,性能更好,但是也没有了依赖注入功能。
    js2854
        15
    js2854  
       2022-02-09 13:50:03 +08:00
    好像有现成的轮子,[RxGo]( https://github.com/ReactiveX/RxGo)
    qbhy
        16
    qbhy  
    OP
       2022-02-09 15:52:32 +08:00
    @js2854 还是不太一样,我这个主要是需要容器注入功能,框架中许多地方用到
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1073 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 22:37 · PVG 06:37 · LAX 14:37 · JFK 17:37
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.