目录

OpenResty最佳实践

如果你正在学 Lua 与 openresty,那你就一定知道在开发过程中,调试代码、单元测试是多么的麻烦。这里整理了一些 lua 开发的最佳实践。

简介

openresty 中 lua ide 调试,单元测试比较麻烦;lua 对库的管理比较散漫。在公司生产环境,一般没有外网环境,OpenResty 的安装和 lua 项目的部署都比较麻烦。 结合 Python 的一些经验,在这里整理一下自己对 Lua 的理解,以及 Lua 最佳实践。

OpenResty 安装

对于软件,使用编译方式安装比较好,比如 Ubuntu,apt-get 安装的包一般都会比较旧。如下介绍我的编译参数。这里需要自己下载自己的依赖包:naxsi, nginx-goodies-nginx-sticky-module-ng,pcre,openssl,zlib,并根据我的配置进行修改相应参数

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
./configure --prefix=$HOME/openresty \
 --add-module=$HOME/openresty/setupfile/third/naxsi-0.55.3/naxsi_src \
 --add-module=$HOME/openresty/setupfile/third/nginx-goodies-nginx-sticky-module-ng \
 --with-pcre=$HOME/openresty/setupfile/depency/pcre-8.41 \
 --with-openssl=$HOME/openresty/setupfile/depency/openssl-1.0.2k \
 --with-zlib=$HOME/openresty/setupfile/depency/zlib-1.2.11 \
 --with-http_v2_module \
 --with-http_sub_module \
 --with-http_stub_status_module \
 --with-http_realip_module \
 --with-cc-opt=-O2 \
 --with-luajit

安装 luarocks

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
./configure --prefix=$HOME/openresty/luajit \
    --with-lua=$HOME/openresty/luajit \
    --lua-suffix=jit \
    --with-lua-include=$HOME/openresty/luajit/include/luajit-2.1

--prefix 设定 luarocks 的安装目录
--with-lua 则是系统中安装的 lua 的根目录
--lua-suffix 版本后缀,此处因为openresyt的lua解释器使用的是 luajit ,所以此处得写 jit
--with-lua-include 设置 lua 引入一些头文件头文件的目录
make build && make install

lua 面向对象

lua 借助 table 以及 metatable 的概念进行 oo 的。这里摘了一个博客的代码,看起来还可以。以后可以使用这个。Lua 中实现面向对象。 这里要说一下 lua 中.运算和:的区别,a={};a.fun(a, arg) 等价于 a:fun(arg),其实就是:可以省略 self 参数。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
local _class={}
function class(super)
    local class_type={}
    class_type.ctor=false
    class_type.super=super
    class_type.new=function(...)
            local obj={}
            do
                local create
                create = function(c,...)
                    if c.super then
                        create(c.super,...)
                    end
                    if c.ctor then
                        c.ctor(obj,...)
                    end
                end
                create(class_type,...)
            end
            setmetatable(obj,{ __index=_class[class_type] })
            return obj
        end
    local vtbl={}
    _class[class_type]=vtbl

    setmetatable(class_type,{__newindex=
        function(t,k,v)
            vtbl[k]=v
        end
    })
    if super then
        setmetatable(vtbl,{__index=
            function(t,k)
                local ret=_class[super][k]
                vtbl[k]=ret
                return ret
            end
        })
    end

    return class_type
end

基本编码规范 设计

可以参考 OpenResty 的最佳实践,平时用起来,大部分跟 c 的风格差不多吧。主要是所使用的代码风格要统一。

包管理

lua 下有两个包管理系统,LuaDist 和 LuaRocks

单元测试

  • 重点 如下方法请在命令行中使用类似curl localhost/unittest进行测试,浏览器中看会很痛苦
  • OpenResty 最佳实践-单元测试给出一种方法。我的处理方法是,在 nginx.conf 中的 server 中建一个单独的 location,content_by_lua_file 设置 unittest.lua。公司用的 verynginx,所以我把此配置放到了 router.lua 中(当然配置方法类似,这个很容易研究,就不放到这里了)。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
-- file: unittest.lua
local _M = {}
local csrf_test = require("test.test_csrf")
local tmp_test = require("test.tmp_test")
function _M:run_unittest()
    csrf_test:run()
end
return _M

-- file: test_csrf.lua
local iresty_test = require("resty.iresty_test")
local json = require("json")
local config = require("config")
local csrf_config = require("csrf_config")
local token = require("token")
local tabletls = require("tabletls")
local tb = iresty_test.new({unit_name="test_csrf"})

local function assert_eq(wanted, real, msg)
    if wanted ~= real then
        error(msg or "error", 2) -- 请注意参数 2
    end
end
local function assert_not_eq(wanted, real, msg)
    if wanted == real then
        error(msg or "error", 2)
    end
end
function tb:test_geturl()
	assert_eq("/unittest", ngx.var.uri, "the unittest url changed")
end
function tb:run_unittest()
    tb:run()
end
return tb
  • 如上有一个很有意思的地方,error(msg or "error", 2),其中的 2 有些讲究,表示返回调用函数所在行,还有 0(忽略行号),1(error 调用位置行号)
  • 性能测试 代码覆盖率 API 测试等,都可以去OpenResty 最佳实践中找,配置很简单。

远程调试 OpenResty

  • 对于此部分,对于有些人来说,使用日志就已经足够了。可对于有些时候,在代码中太多的日志有不利于维护。这里自己要尽力做好日志和调试的平衡吧。
  • 此调试方法适用于 win linux osx
  • 先贴这里用到的 luaIDE 地址:ZeroBraneStudio
  • 如下为安装步骤:
  • 下载这个项目,ZeroBraneStudio,解压可以直接用【调试方法在下载好的文件中 README.md 中有相应的链接】
  • 启动 ZBS,Project -> Start Debugger Server
  • 复制/lualibs/mobdebug/mobdebug.lua -> nginx lua path,
  • 复制/lualibs/socket.lua -> nginx lua path,
  • 复制/bin/clibs/socket/core -> socket 设为 nginx lua cpath(调试时候,使用的是 require(“socket.core”)形式导入包。这里需要注意 core 文件后缀,win 是 dll,linux 是 so,)
  • nginx 配置好,将如上依赖加到 nginx.conf 中,让 lua 可以找到这些文件即可
  • 创建需要调试的 lua 文件
1
2
3
4
5
require('mobdebug').start('192.168.1.22')
local name = ngx.var.arg_name or "Anonymous"
ngx.say("Hello, ", name, "!")
ngx.say("Done debugging.")
require('mobdebug').done()

注:start()呼叫需要运行 IDE 的计算机的 IP 。默认情况下使用“localhost”,但是由于您的 nginx 实例正在运行,因此您需要指定运行 IDE 的计算机的 IP 地址(在我的例子中 192.168.1.22)

  • 在 ide 中打开需要调试的如上 lua 文件
  • Project -> Project Directory -> Set From Current File。
  • 此时,打开浏览器,访问需要此文件处理的链接
  • 此时开始调试 /media/img/Lua/openresty_awesome/debug.png
  • 注:在最下侧有 Remote console,在这里可以执行任何 ngx lua 语句
  • 如上流程没有截图,或者没有说清楚,可以来这里

nginx 一些技巧

  • 看我配置的 nginx.conf
1
lua_package_path '$prefix/lua_script/?.lua;;';

资料