最近在折腾 lua 语言的 web 服务器框架,需要实现路由模块。
以前使用过这个 APItools/router 做路由,是一个比较简单的实现,这里 hanxi/skynet-demo 可以看到使用示例。
参考了 lor 框架的路由实现,它的路由模块使用的是一个纯 lua 实现的 trie 树,看上去挺复杂的,不太好拆出一个独立的模块。
搜到了 libr3 这个库,看描述性能很高,且接口比较简单。并且 iresty/lua-resty-libr3 也对它做了封装,说明质量很定是没啥问题的。已经有人写好了为什么不用呢?
首先我计划的 web 框架是基于 skynet 的,使用的是 lua 不是 luajit,虽然 lua 也有 ffi 库可以使用,我还是想用 lua 的原生方式来封装一下。另一个原因是我用不到 host 和 remote_addr 这两个参数,这两个参数对于 API 网关开发肯定是有用的,但是对于 web 应用开发是用不上的。
参考了 iresty 的封装代码,实现的方式也打算使用 iresty 的方式,一个 so 文件,一个 lua 文件。 so 文件提供基础接口, lua 文件实现主要的路由逻辑。
逻辑全部写在 C 语言里,使用一个 so 也是能做到的,逻辑也不多。但是如果要像 iresty 那样实现 path 的缓存功能,在 C 里实现的话代码就不简洁了。
这个方案纠结了许久,使用一个 so 的话,方便使用者,只需要拷贝一个 so 文件就可以使用, 使用 so + lua 的方式又可以做到代码简洁。最后还是选用了代码简洁的方式,因为使用者使用起来也不麻烦,只需要把 so 和 lua 放到对应的搜索路径即可。
先设计好使用接口:
- 创建树
M:create(cap)
- 插入节点
M:insert(path, method, data)
- 编译
M:compile()
- 查找节点
M:match(path, method)
销毁树放到元表的 __gc
里面。
data 不直接存入 libr3 的树里,像 iresty 一样,只存入索引即可。
不像 iresty 一样提供 dispatch 接口直接调用注入的 callback,而是提供 find 接口,方便使用者根据自己的需要是执行 callback,还是使用数据去干别的事情。这个可以参考 gin 框架的代码,也是提供查询数据的接口的。另外我将要实现的 web 框架也借鉴了 gin 的思路。
目前这个库还只实现了 C 库部分,代码已开放 hanxi/lua-r3 ,感兴趣的可以提前看看。
对 skynet 感兴趣的话,可以学习下这门课程:《Skynet 游戏服务器开发实战》,课程地址: https://www.lanqiao.cn/courses/2770 ,九折优惠邀请码: 2CZ2UA5u
。
使用 skynet 开发的 web 框架也见过几个,没有遇到合心意的。提前预告下,我写的 web 框架参考了 lor , gin ,webpy 等框架的实现,面世还没那么快,还在慢慢打磨。有时候遇到一个方案的抉择要推敲很久。
2021-02-03 更新
https://github.com/hanxi/lua-r3 已实现 Lua 封装部分。