分享我的第一个 GO 开源项目(xujiajun/gorouter),一个简单高性能的 router,和 julienschmidt/httprouter 差不多快,且支持正则 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
xujiajun001
V2EX    Go 编程语言

分享我的第一个 GO 开源项目(xujiajun/gorouter),一个简单高性能的 router,和 julienschmidt/httprouter 差不多快,且支持正则

  •  
  •   xujiajun001
    xujiajun 2018-10-30 13:42:01 +08:00 4827 次点击
    这是一个创建于 2539 天前的主题,其中的信息可能已经有所发展或是发生改变。

    分享我的第一个 GO 开源项目( xujiajun/gorouter ),一个简单高性能的 router,和著名的 julienschmidt/httprouter 差不多快,且支持正则。很方便写 RESTful APIs 或者组建你自己的 web 框架。

    项目由来

    一开始学习 golang 的时候,我是从学习 go 写 web 应用,自然而然需要一个 web 框架或者 web 路由器。

    找到这个 julienschmidt/httprouter (有几千 star 吧,截止今天 10 月 30 号,有 7900+star ),

    使用了下,发现一般功能有了,但是看了他的 import 库,不支持正则,想改他的代码,发现各种 if,嵌套 walk 有种 bad smell 的感觉,还是放弃。我又试用了另一款著名的路由器 gorilla/mux (也有几千 star 吧,截止今天 10 月 30 号,有 7000+star ),测了下功能比 julienschmidt/httprouter 强大,但是性能差太多。具体见我的 benchmarks。

    于是我决定自己写一个,一来学习下 go,二来也能解决下这个问题。我给自己的目标:

    • 0、简单
    • 1、测试覆盖率 90%以上,
    • 2、支持基本的路由功能,
    • 3、支持正则
    • 4、性能要高
    • 5、文档要完善
    • 6、原生 go 实现,不要第三方库

    项目地址

    https://github.com/xujiajun/gorouter

    项目原理

    用了数据结构压缩 Trie

    Features:

    • Fast - see benchmarks
    • URL parameters
    • Regex parameters
    • Routes groups
    • Custom NotFoundHandler
    • Custom PanicHandler
    • Middleware Chain Support
    • Serve Static Files
    • Pattern Rule Familiar
    • HTTP Method Get、Post、Delete、Put、Patch Support
    • No external dependencies (just Go stdlib)

    项目情况

    • 目前项目已经提交给awesome-go了,已经被收录了,也算给 Go 社区贡献自己小小的力量。希望大家用得上。

    • 代码覆盖率 100%。

    • examples 里面含有完整例子,方便学习使用,如编写中间件、路由组、路由正则匹配等。

    • README 用英文写的,已经完成差不多了,中文如有必要,我再补上。我建议大家看英文

    最后,最重要的是欢迎大家给我 star ! 提 issues !提交 PR !和我交流!

    谢谢关注!后面还有更多 Go 开源作品分享给大家

    29 条回复    2018-11-26 09:31:41 +08:00
    hellos
        1
    hellos  
       2018-10-30 14:18:39 +08:00 via Android
    支持,支持
    xujiajun001
        2
    xujiajun001  
    OP
       2018-10-30 14:20:36 +08:00
    @hellos 谢谢:)
    vus520
        3
    vus520  
       2018-10-30 14:22:17 +08:00
    Cool
    lbp0200
        4
    lbp0200  
       2018-10-30 14:50:11 +08:00
    先 star,有空再看
    xujiajun001
        5
    xujiajun001  
    OP
       2018-10-30 15:01:20 +08:00
    @vus520 谢谢关注
    xujiajun001
        6
    xujiajun001  
    OP
       2018-10-30 15:01:34 +08:00
    @lbp0200 谢谢支持
    E1n
        7
    E1n  
       2018-10-30 16:47:21 +08:00
    厉害啊
    xujiajun001
        8
    xujiajun001  
    OP
       2018-10-30 17:24:02 +08:00
    @E1n 谢谢关注
    EchoUtopia
        9
    EchoUtopia  
       2018-10-30 21:26:34 +08:00
    为啥我看你跑 benchmark 的时候,mux 使用的正则路由,而你的没有跑正则路由呢。。还是说我看错了。。
    EchoUtopia
        10
    EchoUtopia  
       2018-10-30 21:49:38 +08:00
    我把 benchmark 里 gorouter 跑 githubapi2,结果 7 分钟还没出结果,改回 githubapi 后,2 分钟跑出来了,是 gorouter 跑正则路由太慢了么,还是什么原因
    xujiajun001
        11
    xujiajun001  
    OP
       2018-10-31 09:40:08 +08:00
    @EchoUtopia 你好,谢谢关注。githubAPI2 是单独给 gorilla/mux 压测用的,他的部分语法如 /user/{user} xujiajun/gorouter 不支持。只用当用到正则的时候,才回有{},其他都是 :开头 的类似 /user/:id 所以你会在我的 benchmark 看到其他待测的几个 router 都是跑 githubAPI,而 gorilla/mux 用的是 githubAPI2。
    PS: xujiajun/gorouter 的语法规则 借鉴了 julienschmidt/httprouter 和 gorilla/mux,支持快捷方式关键词 :id (就会去匹配 id:[0-9]+) ,具体见: https://github.com/xujiajun/gorouter#pattern-rule
    ehlxr
        12
    ehlxr  
       2018-10-31 09:43:29 +08:00
    很棒,支持
    EchoUtopia
        13
    EchoUtopia  
       2018-10-31 09:55:37 +08:00
    @xujiajun001 我个人认为你这个 benchmark 可能不公平,githubapi2 的压测结果和 githubapi 压测结果就不应该放一起比较。你应该分两组,一组 githubapi,一组 githubapi2 但不包含{keyword}这种 url,第一组所有路由都跑,第二组 gorouter 和 mux 跑。
    xujiajun001
        14
    xujiajun001  
    OP
       2018-10-31 10:33:10 +08:00
    @ehlxr 谢谢支持
    xujiajun001
        15
    xujiajun001  
    OP
       2018-10-31 10:36:02 +08:00
    @EchoUtopia 好的 谢谢 你的建议。
    xujiajun001
        16
    xujiajun001  
    OP
       2018-10-31 18:00:43 +08:00
    @EchoUtopia 你好,你可以压测下,切换到 develop 分支: https://github.com/xujiajun/gorouter/tree/develop ,增加了 xujiajun/gorouter vs gorilla/mux (用的是 githubapi2 ),这是我的笔记本跑出来的结果,仅供大家参考:

    ```
    gorouter git:(develop) go test -bench=.
    GithubAPI Routes: 203
    GithubAPI2 Routes: 203
    HttpRouter: 37464 Bytes
    trie-mux: 133864 Bytes
    MuxRouter: 1378528 Bytes
    GoRouter1: 85744 Bytes
    GoRouter2: 85376 Bytes
    goos: darwin
    goarch: amd64
    pkg: github.com/xujiajun/gorouter
    BenchmarkTrieMuxRouterWithGithubAPI-8 10000 624425 ns/op 1086461 B/op 2975 allocs/op
    BenchmarkHttpRouterWithGithubAPI-8 10000 556136 ns/op 1034357 B/op 2604 allocs/op
    BenchmarkGoRouter1WithGithubAPI-8 10000 601101 ns/op 1034412 B/op 2843 allocs/op
    BenchmarkGoRouter2WithGithubAPI2-8 10000 676998 ns/op 1058368 B/op 3177 allocs/op
    BenchmarkMuxRouterWithGithubAPI2-8 10000 5414811 ns/op 1219148 B/op 4430 allocs/op
    PASS
    ok github.com/xujiajun/gorouter 78.775s
    ```

    可以看出 xujiajun/gorouter 性能比 gorilla/mux 好一个数量级
    EchoUtopia
        17
    EchoUtopia  
       2018-10-31 18:25:23 +08:00
    @xujiajun001 #16 赞一个,另外提一个建议,同一个路径,可以限制只能使用这三种:name, {name:regexp}, :name 匹配方式的一种
    xujiajun001
        18
    xujiajun001  
    OP
       2018-11-01 09:24:16 +08:00
    @a href="/member/EchoUtopia">EchoUtopia 你说只能使用这三种 :name 两个一样的?是不是你写错了?欢迎去我的项目里面提 issure 哦。这样方便我统一处理,thanks。https://github.com/xujiajun/gorouter
    EchoUtopia
        19
    EchoUtopia  
       2018-11-01 09:28:49 +08:00 via Android
    @xujiajun001 我的意思是你的三种通配符或正则可能会冲突,有些路由是不允许冲突的,有些是有明确优先级的
    xujiajun001
        20
    xujiajun001  
    OP
       2018-11-01 09:54:40 +08:00
    @EchoUtopia 很好的建议。这个问题我有考虑过,目前设计的是先进先出原则. 把权力开放给使用者,所以在设计路由的时候,设计者自己要注意。尽量不要设计成 :name, {name:regexp}这种差不多的路由
    dangerwolf
        21
    dangerwolf  
       2018-11-05 17:38:32 +08:00
    请问一下,您这个可以直接输出 JSON 吗?我简单看了一下,好像没有相关的。
    xujiajun001
        22
    xujiajun001  
    OP
       2018-11-05 19:56:46 +08:00
    @dangerwolf 你好,这个是单纯的 router,要直接输出 json,你指的是业务逻辑的数据库的交互吧。这个我这边也开发一个库,是个支持 mysql 的 sqlbuilder,地址: https://github.com/xujiajun/godbal,这个库可以直接操作数据库,你可以看下这个库里面的 examples,支持直接输出 json,配合 xujiajun/gorouter 一起使用。
    dangerwolf
        23
    dangerwolf  
       2018-11-06 09:07:45 +08:00
    @xujiajun001 我是想使用框架或者包,直接输出符合 restful 的 json。当然数据来源肯定是从数据库,有个 orm 是最好的。
    其实是想写 API 接口。
    xujiajun001
        24
    xujiajun001  
    OP
       2018-11-06 09:53:37 +08:00
    @dangerwolf 嗯 。如果你要用 xujiajun/gorouter,你只要再找一个支持数据的操作库( ORM 或者 SQL builder 或者你自己封装), 你可以试试我这个库,比 orm 简单,可以直接输出 json,是个 sql builder: https://github.com/xujiajun/godbal
    woniuge
        25
    woniuge  
       2018-11-21 19:47:50 +08:00
    @xujiajun001

    https://github.com/xujiajun/gorouter/blob/master/router.go#L145
    我看见好多不必要的 string 转换,可以直接这样写 if segment[0] == ':' {....}
    woniuge
        26
    woniuge  
       2018-11-21 20:03:27 +08:00
    https://github.com/xujiajun/gorouter/blob/master/router.go#L149-L155


    多余的判断

    ```go

    if One== nil {
    return "", errGenerateParameters
    }
    if one != nil {
    segments = append(segments, key)
    continue
    }

    ```

    ```go

    if one != nil {
    segments = append(segments, key)
    continue
    }else{
    return "", errGenerateParameters
    }

    ```
    xujiajun001
        27
    xujiajun001  
    OP
       2018-11-23 14:50:49 +08:00
    @woniuge 这位兄弟 有心了 谢谢帮我在看代码。欢迎提交给我 PR,这样我会第一时间看到。

    关于第一个问题,你说道:“不必要的 string 转换,可以直接这样写 if segment[0] == ':' {....}” ,我表示不认同。如果不加 string,会有问题的,因为 segment[0] 和 ":" 类型都不一样

    关于第二个问题,其实是个人喜好代码风格不同,我比较倾向于少用 else。但我表示认同写的代码存在冗余,但不是“多余”,我已经改了 https://github.com/xujiajun/gorouter/blob/master/router.go#L149-L155
    woniuge
        28
    woniuge  
       2018-11-23 16:49:59 +08:00
    @xujiajun001 不好意思.看的不够仔细,没注意到 segment 是 string
    xujiajun001
        29
    xujiajun001  
    OP
       2018-11-26 09:31:41 +08:00
    @woniuge 没事 谢谢关注
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     6055 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 39ms UTC 02:13 PVG 10:13 LAX 19:13 JFK 22:13
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86