lua web 框架开发笔记

看到很多简洁的 web 框架,总想自己造个轮子试试,边写边记录些比较。

参考框架

既然是造轮子,我当然选自己最熟悉的 Lua 语言了,可是已经有了基于 Openresty 的 lor 框架,所以底层我就又选用了我熟悉的 skynet 了。

明确目标: 基于 skynet 开发一个 web 框架。

web 框架都有些什么

主要功能

其他东西

轮子取舍

为了早点出轮子,且轮子是可玩的,我对功能做了取舍。计划第一个版本只完成下面这些功能:

为什么不实现模板呢?在现在,前后端分离开发的趋势下,模板显得没那么重要了。服务器只需要提供接口就行,模板都转移到了前端。

重定向的功能本来是计划中的,但是觉得不实现它也没什么问题,等需要的时候再补上吧。

版本规划

第一个版本定为 0.01 ,主要功能就是上面说的。后续版本现在也只是想想而已,比如目前只能在 Linux 下运行,可以尝试迁移到 Mac OS 和 Windows 下运行,因为不是必须的东西,所以就放在 TODO 计划中了。

开发路线

1. 根据参考的框架,确定框架

从使用者的角度来确定框架结构。首先是方便开发部署,所以参考了 lor 的方式,提供脚手架生成工程,工程中包含些操作脚本,比如 start.sh , stop.shreload.sh 这些。由于选用的底层是 skynet ,所以按照 skynet 推荐的方式开发,以 skynet 为 submodule 。

预定的目录结果大概是这样的:

.
├── 3rd
├── conf
├── luaclib
├── lualib
├── Makefile
├── service
└── skynet

框架的主要代码都放在 lualib 目录,其他第三方库都放到 3rd 目录。service 是自定义的 skynet 服务目录。

框架使用 skynet 的特性很少,只用到了 2 种服务,一个主服务 main 和多个 agent 服务,web 开发逻辑都在 agent 服务上执行。

              +---------+    +---------+
              | agent 1 <----+  client |
+-------+     +---------+    +---------+
|  main +-----+
+-------+     +---------+
              | agent 2 |
              +---------+

2. 首先让框架跑起来

首先就是参考 skynet/examples/simpleweb.lua 示例开启 http 服务。这里的例子把 agent 服务写在了同一个文件,把他拆开为 service/main.lualualib/wlua/agent.lua 两个文件,稍微改改就跑起来了。

3. 代码架构设计

首先从使用者的角度来设计框架,使用者的目录结构大致是这样的:

.
├── app
│   └── main.lua
├── conf
│   └── wlua.conf
├── cutlog.sh
├── kill.sh
├── reload.sh
├── start.sh
└── stop.sh

可以看出,除了那些 sh 脚本,只有两个文件是主要的。 app/main.lua 就是 agent 服务的入口,也是使用者开发 web 服务器的入口。 conf/wlua.conf 是配置文件,我想要的 app/main.lua 是这样的结构,和 lor 框架的非常类似。

local wlua = require "wlua"
local app = wlua:new()

app:get("/", function (c)
    c:send("Hello wlua!")
end)

app:run()

跟 lor 还是有点区别的,这里参考了 gin 框架的样式,回调函数的参数只有 c ,是 context 对象,这个对象包含了此次客户端请求的所有信息和相关的操作。

app 这个对象也参考了 gin 框架的 engine 对象,代码结构也和 gin 框架类似。lualib 目录结构是这样的:

lualib/
├── config.lua
├── log.lua
├── middleware
│   └── logger.lua
├── r3.lua
├── util
│   ├── date.lua
│   ├── file.lua
│   ├── json.lua
│   ├── string.lua
│   └── table.lua
├── wlua
│   ├── agent.lua
│   ├── context.lua
│   ├── methods.lua
│   ├── request.lua
│   ├── response.lua
│   └── routergroup.lua
└── wlua.lua

wlua.lua 就是上面 app 对象的类的实现。wlua 类主要包含了 routerrouter 最初是采用的是很简单的 APItools/router.lua ,只要代码能跑起来随时都能把它替换掉。最后发现了一个性能很强的路由库 c9s/r3 ,参考了 iresty/lua-resty-libr3 的封装,自己封装成 hanxi/lua-r3 。主要接口代码就是上面的 r3.lua 文件,之前封装的时候也写过一篇相关文章记录 https://blog.hanxi.cc/p/49

一个客户端请求包含什么呢?主要就者两个:

基本就是请求和回应了,context 把 request 和 response 组合在一起,方便使用者操作。

中间件也参考了 gin 的中间件接口和实现,也实现了一个 logger 中间件来输出 access log 。采用 use 来使用中间件,中间里采用 c:next() 函数来执行后续的 handlers 函数。

实现的 http method 就是下面这些,也基本够用了。

local M = {
    GET     = true,
    POST    = true,
    PUT     = true,
    DELETE  = true,
    PATCH   = true,
    HEAD    = true,
    OPTIONS = true,
}
return M

最后

统计了下 lualib 目录下的代码,也就 820 行,还是很简洁的,开发过程中的看板可以参考下 https://github.com/hanxi/wlua/projects/1

目前除了精简,就只剩下不足了,比如没有实现重定向接口。而且 reload 目前还是有点粗鲁的,只是发个消息退出,如果有挂起的逻辑,会造成逻辑只跑了一半就退出了,还是有优化的余地的。

另外想学 skynet 的话,可以试试我写的这门实战课程 《Skynet 游戏服务器开发实战》 , 地址: https://www.lanqiao.cn/courses/2770 优惠邀请码: 2CZ2UA5u

相关链接

点击进入评论 ...