Gem 做了个使用前缀树的 router,可供 mruby 使用

cichol · 2017年10月11日 · 最后由 jasl 回复于 2017年10月11日 · 2050 次阅读

repo: https://github.com/CicholGricenchos/Mrouter

最近遇到用 ngx_mruby 匹配路由的需求,我们网站曾经有两三百条为了 SEO 做的 url,大概是这个样子:

get 'office-supplies(.:format)' => 'catalog#category', :id => 2, :lang=>'en', :version => 'v1'
get 'computers-and-parts(.:format)' => 'catalog#category', :id => 3, :lang=>'en', :version => 'v1'
get 'accessories(.:format)' => 'catalog#category', :id => 4, :lang=>'en', :version => 'v1'
get 'office-supplies/:name(.:format)' => 'catalog#category', :id => 2, :lang=>'en', :version => 'v1'
get 'computers-and-parts/:name(.:format)' => 'catalog#category', :id => 3, :lang=>'en', :version => 'v1'

现在要做前后端分离的手机版,老板不想放弃这些链接,把这些都打包进 js 又会增加体积,干脆就在 nginx 上匹配了。

mruby 目前还没有现成的 router,看了一下 mustermann,用了新语法不好移植。而且 mustermann 是用正则一行一行匹配,在我们这种用例可能动不动就要匹配三百多次,性能也不好。我觉得用前缀树做是比较合适的,以后可能还可以搞成 dfa,所以就自己造了个轮子。

性能测试下来,匹配单行路由耗时是 mustermann 的 9 倍左右,但是当总路由数到几十以上,优势就比较明显了。有空的话改用 c 写应该更好一些。

虽然这个 gem 是为 mruby 搞的,但是 ruby 也是能用的,当然现在功能还很简单,有需要再加吧。。。

哇 用 ngx_mruby 啦

hooopo 回复

是的,不得不用啊。。手机和 pc 一定要相同的 url,就是读 session 也得用 mruby 了。。感觉很头疼

没有考虑 (/page/:page)(/per_page/:per_page) 这种情况吧?我记得 Trie 这种不好做

jasl 回复

是指匹配不到 /per_page/34/page/12
这个可能得反过来加个定义,毕竟定义本身也没表达出可以反过来,别的应该还好吧

cichol 回复

这个要生成四条匹配

/page/:page
/per_page/:per_page
/
/page/:page/per_page/:per_page
jasl 回复

这些是可以的:

router = Mrouter.new
router.add_route '(/page/:page)(/per_page/:per_page)', '233'

p router.match '' # => {:tag=>"233"}
p router.match '/page' # => false
p router.match '/page/12' # => {:page=>"12", :tag=>"233"}
p router.match '/per_page/12' # => {:per_page=>"12", :tag=>"233"}
p router.match '/page/12/per_page/34' # => {:page=>"12", :per_page=>"34", :tag=>"233"}

我在遇到 ( 的时候直接让 trie 分叉了,然后匹配的时候是深度优先匹的。这样做可能 trie 重复的部分多一点,不过匹配是没问题的。

cichol 回复

那不错,之前我看过 go 的,这种情况没做处理

需要 登录 后方可回复, 如果你还没有账号请 注册新账号