ObjC/Swift 在 Swift 下实现了 Rails 风格的路由库

jasl · 发布于 2016年02月28日 · 最后由 angelfan 回复于 2016年08月30日 · 2014 次阅读
1107

继续为Swift节点添砖加瓦...

项目地址:https://github.com/jasl/RouterX

最终下决定造这个轮子主要有几个动机:

  • 一篇来自天猫团队的分享 解耦神器 —— 统跳协议和Rewrite引擎
  • 之前帮公司的iOS团队设计过推送跳转指定到特定界面、从应用外部通过自定义Scheme跳转到应用内指定界面
  • 最近刚刚为网站添加iOS Universal links 支持(大致原理是在网站根目录建立一个配置文件,访问指定域的所有URL都会自动跳转到应用,iOS会将用户访问的URL传递给应用)。

我发现这几个场景的需求都是一致的并且和我们熟知的Web框架中的路由层相似。

利用双休日分析了下C#的ASP.net MVC、PHP的Laravel、Symphony,Go的HttpRouter还有若干小型的Web框架和iOS的Router库,首先先给一个结论:

Rails是Web开发最强框架绝对不是偶然的,Journey(tenderlove为Rails设计的路由规则解析库)的原理是为路由设计了一门表达式语言(使用RACC定义),然后构造出AST进行匹配,没有任何一个语言的同类库把这个问题上升到如此高度去解决。

这并不是炫技,通过这个方式可以实现很多其他途径很难做到的功能并且保持在匹配时的高性能,比如:/articles/(/page/:page)(/sort/:sort) 这种双可选的情况,除了Rails没有任何一家可以支持。

另外,Journey可以把定义好的路由导出成状态迁移图,进行可视化浏览,在Rails Console下输入 File.write 'fsm.html', app._routes.router.visualizer 然后去项目目录打开 fsm.html 即可 tenderlove的示例

不过,Journey的Parser因为是用RACC生成的,Swift下没有类似工具,此外代码没有文档,写得也比较绕(我是没读懂...),所以 RouterX 是基于我的思路实现的,目前功能已经完成。

一个典型的复杂路由:/articles(/page/:page(/per_page/:per_page))(/sort/:sort)(.:format) 可以正确的生成AST匹配如下模式

/articles
/articles/sort/:sort
/articles/sort/:sort.:format
/articles/page/:page
/articles/page/:page/sort/:sort
/articles/page/:page/sort/:sort.:format
/articles/page/:page/per_page/:per_page
/articles/page/:page/per_page/:per_page/sort/:sort
/articles/page/:page/per_page/:per_page/sort/:sort.:format
/articles/page/:page/per_page/:per_page.:format
/articles/page/:page.:format
/articles.:format

也可以正确的进行匹配,主要代码都已经用单元测试覆盖好。

我没学过编译原理,之前有请教过 @luikore 大神一些问题,消化一下看看如何重构让代码质量和性能更好。

PS:对Rails的路由原理感兴趣的同学可以读一下 Journey into Rails Routing -- an under the hood look at how routing works Rex, Rexical and Rails routing 这两篇文章(这个Blog的文章都挺不错的),不过作者后来也是坑掉了...

Go的 HttpRouter 是利用Trie数据结构实现的,在README里有讲原理,比较有意思。

共收到 5 条回复
18683

学习了!

1107 jasl 尝试理解 ActionDispatch::Routing::RouteSet 中提及了此贴 08月29日 16:10
15307

初次看Journey真的有种望而却步的赶脚 不知道大大是如何看源码的 有什么技巧可以分享嘛

24996

#3楼 @angelfan 好帖子,要看懂Journey需要一些编译原理知识,最基本的需要指定,语法分析,语义分析,LR, AST,等语言设计的前端概念. 在工具上需要会使用Yacc, Flex.

1107

#3楼 @angelfan Journey的代码可读性比较差,而且parser是通过RACC生成的,就没有阅读意义了

路由匹配这块我建议学习 https://github.com/sinatra/mustermann

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