lua-nginx-module 模块
在openresty中,lua-nginx-module
是一个基础的模块,这个模块中暴露出去了很多的API可以供我们来使用。
但是lua-nginx-module
这个模块存在一个问题:模块中调用C函数的API都是使用Lua C API来完成。
对于那些能够被 Lua 调用的 C 函数来说,它的接口必须遵循 Lua 要求的形式:
typedef int (*lua_CFunction)(lua_State* L)
这个代表一个函数指针,参数为lua_State
类型的指针,返回值为一个整型,表示返回值的数量。
例如ngx.base64_decode
这个API:
lua_pushcfunction(L, ngx_http_lua_ngx_decode_base64);
lua_setfield(L, -2, "decode_base64");
上面的C代码的作用是注册了C函数ngx_http_lua_ngx_decode_base64
,这个C函数和ngx.decode_base64
这个对外的API是对应关系。
static int ngx_http_lua_ngx_decode_base64(lua_State *L)
{
ngx_str_t p, src;
src.data = (u_char *) luaL_checklstring(L, 1, &src.len);
p.len = ngx_base64_decoded_length(src.len);
p.data = lua_newuserdata(L, p.len);
if (ngx_decode_base64(&p, &src) == NGX_OK) {
lua_pushlstring(L, (char *) p.data, p.len);
} else {
lua_pushnil(L);
}
return 1;
}
上面的代码是ngx_http_lua_ngx_decode_base64
这个函数的定义,定义中的ngx_base64_decoded_length
和ngx_decode_base64
都是Nginx自身提供的C函数。
用C编写的函数无法把返回值传给Lua 代码,而是需要通过栈,来传递 Lua 和 C 之间的调用参数和返回值。这就意味着这些代码不能被JIT追踪到,也就没有办法进行优化。
lua-resty-core 模块
lua-resty-core 模块的作用就是将 lua-nginx-module 模块中已经有的部分对外暴露的API使用FFI的模式重写了一遍。
也就是说,对于这些重写过的API(比如ngx.base64_decode
),如果开启了 lua-resty-core 模块,那么使用的就是 lua-resty-core 中重写的实现,否则使用的是 lua-nginx-module 中的Lua C API的实现。
在 OpenResty 1.15.8.1 版本前,lua-resty-core 默认是不开启的,而这不仅会带来性能损失,更严重的是会造成潜在的 bug。所以,如果在使用历史版本的时候,建议手动开启 lua-resty-core。只需要在 init_by_lua 阶段,增加一行代码就可以了:
require "resty.core"
lua-resty-core 中不仅重新实现了部分 lua-nginx-module 项目中的 API,比如ngx.re.match
、ngx.md5
等,还实现了不少新的 API,比如ngx.ssl
、ngx.base64
、ngx.errlog
、ngx.process
、ngx.re.split
、ngx.resp.add_header
、ngx.balancer
、ngx.semaphore
等等。
比如新增的nginx.base64
这个API在标准的Base64编解码外,又提供了新的Base64URL的编解码,如下:
local b64 = require "ngx.base64"
local enc = b64.encode_base64url(str) -- 适用于 URL 的 Base64 编码
local dec = b64.decode_base64url(enc_url) -- Base64URL 解码
如上图,就是 lua-resty-core 的目录结构,在目录结构中,nginx
目录下就是新增的API,而core
目录下则是重写的 lua-nginx-module 中的API。