[TOC]
Nginx中使用lua
主要是通过在编译NGINX时添加lua模块和lua的jit需要LuaJIT-2.0.4.tar.gz,ngx_devel_kit,lua-nginx-module
然后在NGINX中配置lua代码解析路径,使NGINX直接将请求转给lua
如下:
./configure --add-module=/root/ngx_devel_kit-0.3.0 --add-module=/root/lua-nginx-module-0.10.8
相当于说是在NGINX中直接编写lua代码
编译NGINX并安装Lua,不带openresty
下载安装LuaJIT-2.0.4.tar.gz
cd /opt \
&& wget -c http://luajit.org/download/LuaJIT-2.0.4.tar.gz\
&& tar xzvf LuaJIT-2.0.4.tar.gz\
&& cd LuaJIT-2.0.4\
&& make install PREFIX=/usr/local/luajit
# luaJit安装完之后默认存储的路径是/usr/local/luajit/
# 所以下面可以直接设置环境变量即可
#注意设置环境变量!后面NGINX会用到
export LUAJIT_LIB=/usr/local/luajit/lib\
&& export LUAJIT_INC=/usr/local/luajit/include/luajit-2.0
下载解压ngx_devel_kit
wget https://github.com/simpl/ngx_devel_kit/archive/v0.3.0.tar.gz\
&& tar -xzvf v0.3.0.tar.gz
下载解压lua-nginx-module
wget https://github.com/openresty/lua-nginx-module/archive/v0.10.8.tar.gz\
&& tar -xzvf v0.10.8.tar.gz
安装nginx-1.10.3.tar.gz
#注意ngx_devel_kit和lua-nginx-module以实际解压路径为准
# make -j2如果报错:objs/Makefile:591: recipe for target 'objs/src/core/ngx_murmurhash.o' failed
# 我在ubuntu18.04下有这个错误
# 在objs/Makefile中将 -Werror 删除,对于warnings忽略
# vim objs/Makefile 找到第三行的CFLAGS = -I/usr/local/luajit/include/luajit-2.0 -pipe -O -W -Wall -Wpointer-arith -Wno-unused -Werror -g -DNDK_SET_VAR
# 删掉-Werrori 即可 具体可以参考NGINX篇的NGINX常见错误收集
# 这里我只编译了luajit的扩展如果需要别的, 可以在nginx篇或docker中找到NGINX的编译语句复制进来
wget http://nginx.org/download/nginx-1.10.3.tar.gz\
&& tar -xzvf nginx-1.10.3.tar.gz\
&& cd nginx-1.10.3\
&& ./configure --add-module=/opt/ngx_devel_kit-0.3.0 --add-module=/opt/lua-nginx-module-0.10.8\
&& make -j2\
&& make install
#将nginx做成命令
ln -s /usr/local/nginx/sbin/nginx /usr/bin/nginx\
&& cd /usr/local/nginx/conf/
Nginx中配置lua
lua的指令方式配置
# 在server 中添加一个localtion
location /lua {
# 关闭缓存,这样调试时每次修改lua代码不需要reload nginx;但是正式环境一定记得开启缓存
lua_code_cache off;
default_type 'text/plain';
# 这里可以直接写lua代码,记得用引号括起来
# 必须用ngx.say("XXX")输出内容,因为print("XXX")的内容会输出到log中
content_by_lua 'ngx.say("hello, lua")';
}
lua文件方式
#在server 中添加一个localtion
location /lua {
# 关闭缓存,这样调试时每次修改lua代码不需要reload nginx;但是正式环境一定记得开启缓存
lua_code_cache off;
default_type 'text/html';
# 相对于nginx安装目录 也可以使用绝对路径
# 在这里的文件中使用print("XXX")是无法在页面中显示的
# 必须用ngx.say("XXX")输出内容,因为print("XXX")的内容会输出到log中
# print定向到了log中去,所以界面上面无法查看到;
content_by_lua_file conf/lua/test.lua;
}
#test.lua文件内容
ngx.say("hello world,I'm lua");
启动nginx(已经做了软连接了,可以在任何目录启动)
# 如果报错nginx: error while loading shared libraries: libluajit-5.1.so.2: cannot open shared object file: No such file or directory
# 使用下面命令建立变量(具体原因可以看Linux篇的常见问题收集)
export LD_LIBRARY_PATH=/usr/local/luajit/lib:$LD_LIBRARY_PATH
# 或者使用下面命令 加载lua库(具体原因可以看Linux篇的常见问题收集)
echo "/usr/local/luajit/lib" >> /etc/ld.so.conf && ldconfig
# 记得需要在编译 luajit 的时候 make install PREFIX=/usr/local/luajit
直接使用 nginx命令进行启动
通过openresty安装全部环境, 安装openresty的两种方式
官方地址https://openresty.org
如果要在NGINX中使用lua来连接Redis就必须要用到openresty
如果只是mysql的话直接用luarocks安装luasql即可
但是NGINX一般肯定是要用Redis的
如果非要用第一种方式来做安装NGINX的lua_module的话, 单独安装openresty应该也可以
但是我没试过, 我想关键点应该是在于
lua_package_path "/usr/local/openresty/lualib?.lua;;"; #lua 模块
lua_package_cpath "/usr/local/openresty/lualib?.so;;"; #c模块
安装openresty之后把这两句话配好应该就没有问题了
当然了我自己是非常喜欢直接用openresty 的因为他把所有东西都安好了, 只要配置NGINX就行了.
自动安装模式安装 openresty,提供官方的预编译包
参考https://openresty.org/cn/linux-packages.html
自动安装这种,一般会安装到'/usr/local/openresty/'中
同时会将nginx luajit等等全部安装都这里,比如NGINX就在/usr/local/openresty/nginx
中
这时候我们cd 进去使用sbin/nginx -V
可以看到Nginx几乎所有的扩展,包括luajit等全部安装了
这时候只要我们配置好conf/nginx.conf
即可使用lua了
- /usr/local/openresty/luajit :luajit 环境,luajit 类似于 java 的 jit,即即时编译,lua 是一种解释语言,通过 luajit 可以 即时编译 lua 代码到机器代码,得到很好的性能;
- /usr/local/openresty/lualib:要使用的 lua 库,里边提供了一些默认的 lua 库,如 redis,json 库等,也可以把一些自 己开发的或第三方的放在这;
- /usr/local/openresty/nginx :安装的 nginx; 通过 /usr/local/openresty/nginx/sbin/nginx -V 查看 nginx 版本和安装的模块
Ubuntu
# 导入我们的 GPG 密钥:
# 可以能需要 apt-get install gnupg gnupg2 gnupg1
wget -qO - https://openresty.org/package/pubkey.gpg | sudo apt-key add -
# 安装 add-apt-repository 命令
# (之后你可以删除这个包以及对应的关联包)
sudo apt-get -y install software-properties-common
# 添加我们官方 official APT 仓库:
sudo add-apt-repository -y "deb http://openresty.org/package/ubuntu $(lsb_release -sc) main"
# 更新 APT 索引:
sudo apt-get update
# 然后就可以像下面这样安装软件包,比如 openresty:
sudo apt-get install openresty
# 这个包同时也推荐安装 openresty-opm 和 openresty-restydoc 包,所以后面两个包会缺省安装上。如果你不想自动关联安装,可以用下面方法关闭自动关联安装:
sudo apt-get install --no-install-recommends openresty
# 可以通过下面命令查看安装目录
whereis openresty
手动安装openresty,编译安装
参考https://openresty.org/cn/installation.html
如果在编译安装时make的时候报错openssl_***之类的错误,一般认为是openssl的接口有改动
这时候我们可以用openresty新版本,或者根据openresty使用openssl版本即可.
同样的,我们在手动编译的时候也是会将openresty很多自带的东西安装过去
而且还可以通过--prefix=XXX
参数指定安装的目录, 通过--with-XX
安装额外的模块,通过--add-module
添加自定义的第三方模块
Ubuntu
# 默认, --prefix=/usr/local/openresty 程序会被安装到/usr/local/openresty目录。
apt-get install wget libpcre3-dev libssl-dev perl make build-essential curl\
&& wget https://openresty.org/download/openresty-1.13.6.2.tar.gz\
&& tar -xzvf openresty-1.13.6.2.tar.gz && cd openresty-1.13.6.2/\
&&./configure
# 可以指定各种选项,比如
./configure --prefix=/opt/openresty \
--with-luajit \
--without-http_redis2_module \
--with-http_iconv_module \
--with-http_postgres_module
# 试着使用 ./configure --help 查看更多的选项。
--with*** 安装一些内置/集成的模块
--with-http_realip_module 取用户真实 ip 模块
-with-pcre Perl 兼容的达式模块
--with-luajit 集成 luajit 模块
--add-module 添加自定义的第三方模块,如此次的 ngx_che_purge
.....
# 安装文件
make -j2 && make install
# 可以通过下面命令查看安装目录
whereis openresty
配置NGINX
#lua模块路径,多个之间”;”分隔,其中”;;”表示默认搜索路径
默认到/usr/local/openresty/nginx下找到nginx的配置文件
在 http 部分添加如下配置
lua_package_path "/usr/local/openresty/lualib?.lua;;"; #lua 模块
lua_package_cpath "/usr/local/openresty/lualib?.so;;"; #c模块
为了方便开发我们在 /usr/servers/nginx/conf 目录下创建一个 lua.conf
在 nginx.conf 中的 http 部分添加 include lua.conf 包含此文件片段
include lua.conf;
在 lua.conf 中 server 部分添加如下配置
server {
listen 500;
server_name _;
location /lua {
default_type 'text/html';
content_by_lua 'ngx.say("hello Im lua code")';
}
}
# 检查配置
/usr/local/openresty/nginx/sbin/nginx -t
# 重新加载NGINX配置
/usr/local/openresty/nginx/sbin/nginx -s reload
# 测试完毕,将lua的代码改为通过文件加载
server {
listen 500;
server_name _;
location /lua {
default_type 'text/html';
lua_code_cache off;
content_by_lua_file conf/lua/test.lua;
}
}
nginx lua模块常用指令
其实有一个pdf文档叫<跟我学Nginx+lua开发>里面对模块的讲解更好,有各种案例,虽然对模块讲的比较少,但是基本上够用了.
lua_code_cache 是否开启代码缓存.
语法:lua_code_cache on | off
默认: on
适用上下文:http、server、location、location if
这个指令是指定是否开启lua的代码编译缓存,开发时可以设置为off,以便lua文件实时生效,如果是生产线上,为了性能,建议开启。
关闭代码缓存后,我们在NGINX中的lua文件汇总的代码有变动,不用重启NGINX.
content_by_lua 指定lua代码块,但是v0.9.17以后不要再用
注意,在v0.9.17发行版之后,不鼓励使用这个指令。而是使用init_by_lua_block指令。
支持正则
充当“内容处理程序”,并为每个请求执行< Lua -script-str>中指定的Lua代码字符串。
Lua代码可以进行API调用,并在独立的全局环境(即沙箱)中作为新生成的协程执行。
# 可以直接在这里写lua程序
content_by_lua 'ngx.say("hello, lua")';
content_by_lua_block 指定Lua代码块
支持正则
与content_by_lua指令类似,只是该指令将Lua源直接内联到一对花括号({})中,而不是在NGINX字符串文本中(这需要特殊的字符转义)。
content_by_lua_block {
ngx.say("I need no extra escaping here, for example: \r\nblah")
}
content_by_lua_file 指定Lua代码的路径
支持正则
指定Lua代码的路径,可以是相对路径也可以是绝对路径.相对路径必须以conf/开始
与content_by_lua等价,除了
可以在
当一个相对路径如foo/bar时。给定lua,它们将被转换为绝对路径,相对于启动Nginx服务器时由-p path命令行选项确定的服务器前缀路径。
当打开Lua代码缓存时(默认情况下),用户代码在第一个请求时加载一次并缓存,每次修改Lua源文件时都必须重新加载Nginx配置。通过在Nginx. conf中关闭lua_code_cache以避免重新加载Nginx,可以在开发期间暂时禁用Lua代码缓存。
Nginx变量在文件路径中支持动态调度,例如:
location ~ ^/app/([-_a-zA-Z0-9/]+) {
set $path $1;
content_by_lua_file /path/to/lua/app/root/$path.lua;
}
我的案例
content_by_lua_file conf/lua/test.lua;
lua_package_path 设置set_by_lua、content_by_lua等脚本指定的Lua模块搜索路径
语法:lua_package_path
默认:LUA_PATH环境变量的内容或Lua的编译内默认值。
适用上下文:http
设置set_by_lua、content_by_lua等脚本指定的Lua模块搜索路径。路径字符串为标准Lua路径形式,且;;可用于表示原始搜索路径。。
例如:lua_package_path "/opt/nginx/conf/www/?.lua;;";
具体的路径设置要参考lua的模块机制
init_by_lua 初始化一些lua的全局变量的代码块,以便后续的代码使用
注意,在v0.9.17发行版之后,不鼓励使用这个指令。而是使用rewrite_by_lua_block指令。
从这段配置代码,我们可以看出,其实这个指令就是初始化一些lua的全局变量的代码块,以便后续的代码使用。
语法:init_by_lua
适用上下文:http
init_by_lua 'cjson = require "cjson"';
server {
location = /api {
content_by_lua '
ngx.say(cjson.encode({dog = 5, cat = 6}))
';
}
}
init_by_lua_block 初始化一些lua的全局变量的代码块,以便后续的代码使用。
从这段配置代码,我们可以看出,其实这个指令就是初始化一些lua的全局变量,以便后续的代码使用。
# this runs before forking out nginx worker processes:
init_by_lua_block { require "cjson" }
server {
location = /api {
content_by_lua_block {
-- the following require() will just return
-- the alrady loaded module from package.loaded:
ngx.say(require "cjson".encode{dog = 5, cat = 6})
}
}
}
init_by_lua_file 初始化一些lua的全局变量的代码文件,以便后续的代码使用。
init_worker_by_lua 在启用主进程时,在每个Nginx工作进程启动时运行指定的Lua代码
注意,在v0.9.17发行版之后,不鼓励使用这个指令。而是使用rewrite_by_lua_block指令。
这个指令最初是在v0.9.5版本中引入的。
自v0.10.12发布以来,这个钩子不再在缓存管理器和缓存加载器进程中运行。
类似于上面的init_by_lua_*,不过是作用在work进程的,先于work进程启动而调用。
在启用主进程时,在每个Nginx工作进程启动时运行指定的Lua代码。当主进程被禁用时,这个钩子将在init_by_lua*之后运行。
这个钩子通常用于为每个worker创建重复发生的计时器(通过ngx.timer)。用于后端健康检查或其他定时例行工作。下面是一个例子,
init_worker_by_lua '
local delay = 3 -- in seconds
local new_timer = ngx.timer.at
local log = ngx.log
local ERR = ngx.ERR
local check
check = function(premature)
if not premature then
-- do the health check or other routine work
local ok, err = new_timer(delay, check)
if not ok then
log(ERR, "failed to create timer: ", err)
return
end
end
end
local hdl, err = new_timer(delay, check)
if not hdl then
log(ERR, "failed to create timer: ", err)
return
end
';
init_worker_by_lua_block在启用主进程时,在每个Nginx工作进程启动时运行指定的Lua代码
与init_worker_by_lua指令类似,只是该指令将Lua源直接内联到一对花括号({})中,而不是在NGINX字符串文本中(这需要特殊的字符转义)。
init_worker_by_lua_block {
print("I need no extra escaping here, for example: \r\nblah")
}
init_worker_by_lua_file在启用主进程时,在每个Nginx工作进程启动时运行指定的Lua代码
类似于init_worker_by_lua,但是接受Lua源文件或Lua字节码文件的文件路径。
这个指令最初是在v0.9.5版本中引入的。
自v0.10.12发布以来,这个钩子不再在缓存管理器和缓存加载器进程中运行。
set_by_lua 让nginx的变量与lua的变量相互作用赋值。
注意,在v0.9.17发行版之后,不鼓励使用这个指令。而是使用set_by_lua_block指令。
语法:set_by_lua $res [$arg1 $arg2 ...]
适用上下文:server、location、location if
location /foo {
set $diff ''; # we have to predefine the $diff variable here
set_by_lua $sum '
local a = 32
local b = 56
ngx.var.diff = a - b; -- write to $diff directly
return a + b; -- return the $sum value normally
';
echo "sum = $sum, diff = $diff";
}
set_by_lua_block 让nginx的变量与lua的变量相互作用赋值.
-
这个指令将Lua源直接内联到一对花括号({})中,而不是在NGINX字符串文本中(这需要特殊的字符转义),并且
-
这个指令不支持像set_by_lua中的那样在Lua脚本之后附加参数。
set_by_lua_block $res { return 32 + math.cos(32) }
# $res now has the value "32.834223360507" or alike.
set_by_lua_file 让nginx的变量与lua的变量相互作用赋值
rewrite_by_lua 实现重定向
注意,在v0.9.17发行版之后,不鼓励使用这个指令。而是使用rewrite_by_lua_block指令。
充当重写阶段处理程序,并为每个请求执行< Lua -script-str>中指定的Lua代码字符串。Lua代码可以进行API调用,并在独立的全局环境(即沙箱)中作为新生成的协程执行。
注意,这个处理程序总是在标准ngx_http_rewrite_module之后运行。因此,以下工作将如预期的那样进行:
location /foo {
set $a 12; # create and initialize $a
set $b ""; # create and initialize $b
rewrite_by_lua 'ngx.var.b = tonumber(ngx.var.a) + 1';
echo "res = $b";
}
因为set $a 12和set $b ""在rewrite_by_lua之前运行。
另一方面,以下工作并不如预期的那样有效:
location /foo {
set $a 12; # create and initialize $a
set $b ''; # create and initialize $b
rewrite_by_lua 'ngx.var.b = tonumber(ngx.var.a) + 1';
if ($b = '13') {
rewrite ^ /bar redirect;
break;
}
echo "res = $b";
}
因为if在rewrite_by_lua之前运行,即使它位于配置中的rewrite_by_lua之后。
正确的做法是:
location /foo {
set $a 12; # create and initialize $a
set $b ''; # create and initialize $b
rewrite_by_lua '
ngx.var.b = tonumber(ngx.var.a) + 1
if tonumber(ngx.var.b) == 13 then
return ngx.redirect("/bar");
end
';
echo "res = $b";
}
注意,ngx_eval模块可以通过使用rewrite_by_lua来近似。例如,
location / {
eval $res {
proxy_pass http://foo.com/check-spam;
}
if ($res = 'spam') {
rewrite ^ /terms-of-use.html redirect;
}
fastcgi_pass ...;
}
可以在ngx_lua中实现:
location = /check-spam {
internal;
proxy_pass http://foo.com/check-spam;
}
location / {
rewrite_by_lua '
local res = ngx.location.capture("/check-spam")
if res.body == "spam" then
return ngx.redirect("/terms-of-use.html")
end
';
fastcgi_pass ...;
}
与任何其他重写阶段处理程序一样,rewrite_by_lua也在子请求中运行。
rewrite_by_lua_block 实现重定向
与rewrite_by_lua指令类似,只是这个指令将Lua源代码内联到一对花括号({})中,而不是在NGINX字符串文本中(这需要特殊的字符转义)。
rewrite_by_lua_block {
do_something("hello, world!\nhiya\n")
}
rewrite_by_lua_file 实现重定向
access_by_lua
注意,在v0.9.17发行版之后,不鼓励使用这个指令。而是使用rewrite_by_lua_block指令。
access_by_lua_block
access_by_lua_file
header_filter_by_lua 用lua的代码去指定http响应的 header一些内容。
注意,在v0.9.17发行版之后,不鼓励使用这个指令。而是使用rewrite_by_lua_block指令。
在< Lua -script-str>中指定的se Lua代码,用于定义输出头过滤器。
请注意,以下API函数目前在此上下文中被禁用:
输出API函数(例如,ngx)。说罢,ngx.send_headers) 控制API函数(例如,ngx)。重定向和ngx.exec) 子请求API函数(例如,ngx.location)。捕获和ngx.location.capture_multi) Cosocket API函数(例如,ngx.socket)。tcp和ngx.req.socket)。 下面是一个在我们的Lua头过滤器中覆盖响应头(或者如果没有添加响应头)的例子:
location / {
proxy_pass http://mybackend;
header_filter_by_lua 'ngx.header.Foo = "blah"';
}
header_filter_by_lua_block 用lua的代码去指定http响应的 header一些内容。
header_filter_by_lua_file 用lua的代码去指定http响应的 header一些内容。
body_filter_by_lua 这个指令可以用来修改http的响应正文的。
注意,在v0.9.17发行版之后,不鼓励使用这个指令。而是使用rewrite_by_lua_block指令。
使用< Lua -script-str>中指定的Lua代码定义输出体过滤器。
输入数据块通过ngx传递。arg1和指示响应体数据流结束的“eof”标志通过ngx传递。arg2。
在后台,“eof”标志只是Nginx链接缓冲区的last_buf(用于主请求)或last_in_chain(用于子请求)标志。(在v0.7.14发布之前,“eof”标志在子请求中根本不起作用。)
输出数据流可以通过运行以下Lua语句立即中止:
return ngx.ERROR
这将截断响应主体,通常会导致不完整且无效的响应。
Lua代码可以通过覆盖ngx将自己修改过的输入数据块传递给下游的Nginx输出体过滤器。带有Lua字符串或Lua字符串表的arg[1]。例如,要转换响应体中的所有小写字母,我们可以这样写:
location / {
proxy_pass http://mybackend;
body_filter_by_lua 'ngx.arg[1] = string.upper(ngx.arg[1])';
}
将nil或空Lua字符串值设置为ngx时。arg[1],没有数据块将被传递到下游的Nginx输出过滤器。
同样,可以通过将boolean值设置为ngx.arg[2]来指定新的“eof”标志。例如,
location /t {
echo hello world;
echo hiya globe;
body_filter_by_lua '
local chunk = ngx.arg[1]
if string.match(chunk, "hello") then
ngx.arg[2] = true -- new eof
return
end
-- just throw away any remaining chunk data
ngx.arg[1] = nil
';
}
body_filter_by_lua_block 这个指令可以用来修改http的响应正文的
与body_filter_by_lua指令类似,只是这个指令将Lua源直接内联到一对花括号({})中,而不是在NGINX字符串文本中(这需要特殊的字符转义)。
body_filter_by_lua_block {
local data, eof = ngx.arg[1], ngx.arg[2]
}
body_filter_by_lua_file 这个指令可以用来修改http的响应正文的
与body_filter_by_lua等价,除了
当一个相对路径如foo/bar时。给定lua,它们将被转换为绝对路径,相对于启动Nginx服务器时由-p path命令行选项确定的服务器前缀路径。
这个指令最初是在v0.5.0rc32版本中引入的。
Nginx中的Lua API
更多 Nginx Lua API 请参考 http://wiki.nginx.org/HttpLuaModule#Nginx_API_for_Lua。
配置文件
example.conf 配置文件
location ~ /lua_request/(\d+)/(\d+) {
#设置nginx变量
set $a $1;
set $b $host;
default_type "text/html";
#nginx内容处理
content_by_lua_file /usr/example/lua/test_request.lua; #内容体处理完成后调用
echo_after_body "ngx.var.b $b";
}
获取请求方式和请求参数以及变量赋值
代码
--nginx变量
local var = ngx.var
ngx.say("ngx.var.a : ", var.a, "
")
ngx.say("ngx.var.b : ", var.b, "
")
ngx.say("ngx.var[2] : ", var[2], "
")
ngx.var.b = 2;
ngx.say("
")
--请求头
local headers = ngx.req.get_headers()
ngx.say("headers begin", "
")
ngx.say("Host : ", headers["Host"], "
")
ngx.say("user-agent : ", headers["user-agent"], "
")
ngx.say("user-agent : ", headers.user_agent, "
")
for k, v in pairs(headers) do
if type(v) == "table" then
ngx.say(k, " : ", table.concat(v, ","), "
")
else
ngx.say(k, " : ", v, "
")
end
end
ngx.say("headers end", "
")
ngx.say("
")
--get请求uri参数
ngx.say("uri args begin", "
")
local uri_args = ngx.req.get_uri_args()
for k, v in pairs(uri_args) do
if type(v) == "table" then
ngx.say(k, " : ", table.concat(v, ", "), "
")
else
ngx.say(k, ": ", v, "
")
end
end
ngx.say("uri args end", "
")
ngx.say("
")
--post请求参数
ngx.req.read_body()
ngx.say("post args begin", "
")
local post_args = ngx.req.get_post_args()
for k, v in pairs(post_args) do
if type(v) == "table" then
ngx.say(k, " : ", table.concat(v, ", "), "
")
else
ngx.say(k, ": ", v, "
")
end
end
ngx.say("post args end", "
")
ngx.say("
")
--请求的http协议版本
ngx.say("ngx.req.http_version : ", ngx.req.http_version(), "
")
--请求方法
ngx.say("ngx.req.get_method : ", ngx.req.get_method(), "
")
--原始的请求头内容
ngx.say("ngx.req.raw_header : ", ngx.req.raw_header(), "
")
--请求的body内容体
ngx.say("ngx.req.get_body_data() : ", ngx.req.get_body_data(), "
")
ngx.say("
")
常用系统变量
ngx.var : nginx 变量,如果要赋值如 ngx.var.b = 2,此变量必须提前声明;另外对于 nginx location 中使用 正则捕获的捕获组可以使用 ngx.var [捕获组数字]获取;
ngx.req.get_headers:获取请求头,默认只获取前100,如果想要获取所以可以调用ngx.req.get_header s(0);获取带中划线的请求头时请使用如 headers.user_agent 这种方式;如果一个请求头有多个值,则返回的 是 table;
ngx.req.get_uri_args:获取 url 请求参数,其用法和 get_headers 类似;
ngx.req.get_post_args:获取 post 请求内容体,其用法和 get_headers 类似,但是必须提前调用 ngx.req.r ead_body() 来读取 body 体(也可以选择在 nginx 配置文件使用lua_need_request_body on;开启读取 bod y 体,但是官方不推荐);
ngx.req.raw_header:未解析的请求头字符串;
ngx.req.get_body_data:为解析的请求 body 体内容字符串。
如上方法处理一般的请求基本够用了。另外在读取 post 内容体时根据实际情况设置 client_body_buffer_size 和 client_max_body_size 来保证内容在内存而不是在文件中。
使用如下脚本测试
wget --post-data 'a=1&b=2' 'http://127.0.0.1/lua_request/1/2?a=3&b=4' -O -
输出响应
NGINX配置
location /lua_response_1 {
default_type "text/html";
content_by_lua_file /usr/example/lua/test_response_1.lua;
}
代码
--写响应头
ngx.header.a = "1"
--多个响应头可以使用table
ngx.header.b = { "2", "3" }
--输出响应
ngx.say("a", "b", "
")
ngx.print("c", "d", "
")
--200状态码退出
return ngx.exit(200)
ngx.header:输出响应头;
ngx.print:输出响应内容体;
ngx.say:通ngx.print,但是会最后输出一个换行符;
ngx.exit:指定状态码退出。
重定向
NGINX配置
location /lua_response_2 {
default_type "text/html";
content_by_lua_file /usr/example/lua/test_response_2.lua;
}
代码
ngx.redirect("http://jd.com", 302)
ngx.redirect:重定向;
ngx.status= 状态码,设置响应的状态码;
ngx.resp.get_headers() 获取设置的响应状态码;
ngx.send_head ers() 发送响应状态码,当调用 ngx.say/ngx.print 时自动发送响应状态码;
可以通过 ngx.headers_sent=true 判断是否发送了响应状态码。
其他 API
NGINX配置
location /lua_other {
default_type "text/html";
content_by_lua_file /usr/example/lua/test_other.lua;
}
代码
--未经解码的请求uri
local request_uri = ngx.var.request_uri;
ngx.say("request_uri : ", request_uri, "
");
--解码
ngx.say("decode request_uri : ", ngx.unescape_uri(request_uri), "
"); --MD5
ngx.say("ngx.md5 : ", ngx.md5("123"), "
")
--http time
ngx.say("ngx.http_time : ", ngx.http_time(ngx.time()), "
")
- ngx.escape_uri/ngx.unescape_uri : uri 编码解码; • ngx.encode_args/ngx.decode_args:参数编码解码;
- ngx.encode_base64/ngx.decode_base64:BASE64 编码解码;
- ngx.re.match:nginx 正则表达式匹配;
Nginx 全局内存
更多 API 请参考 http://wiki.nginx.org/HttpLuaModule#ngx.shared.DICT。
Nginx 是一个 Master 进程多个 Worker 进程的工作方式,因此我们可能需要在多个 Worker 进程中共享数据,那么此时就可以使用 ngx.shared.DICT 来实现全局内存共享。
首先在 nginx.conf 的 http 部分分配内存大小
#共享全局变量,在所有worker间共享 lua_shared_dict shared_data 1m;
location /lua_shared_dict {
default_type "text/html";
content_by_lua_file /usr/example/lua/test_lua_shared_dict.lua;
}
代码
--1、获取全局共享内存变量
local shared_data = ngx.shared.shared_data
--2、获取字典值
local i = shared_data:get("i")
if not i then
i = 1
--3、惰性赋值
shared_data:set("i", i)
ngx.say("lazy set i ", i, "
")
end
--递增
i = shared_data:incr("i", 1)
ngx.say("i=", i, "
")
到此基本的 Nginx Lua API 就学完了,对于请求处理和输出响应如上介绍的 API 完全够用了,更多 API 请参考