-
Notifications
You must be signed in to change notification settings - Fork 8
第十六节、常用指令
Ngx_Lua提供了大量的Lua API指令来实现各种功能,本节会介绍一些常用的指令。
在Nginx中通过rewrite对请求进行重定向,而在Ngx_Lua里可以使用ngx.redirect、ngx.req.set_uri来完成重定向,并且Ngx_Lua还提供了一个具有强大的扩展能力的ngx.exec指令。
语法:ngx.redirect(uri, status?)
配置环境:rewrite_by_lua*,access_by_lua*,content_by_lua*
含义:发出一个 HTTP状态码为301或302的重定向请求到指定的URI。
参数status的可选值有301、302、303、307和308,默认值是302。下面是ngx.redirect重定向和rewrite重定向的对比:
location / {
# 等同于 rewrite ^/ http://testnginx.com/test? redirect;
rewrite_by_lua_block {
return ngx.redirect("/test")
}
}
上述配置使用了默认的302状态。如果在跳转过程中需要保留请求的参数,可作如下配置:
location / {
# 等同于 rewrite ^/ http://testnginx.com/test permanent;
rewrite_by_lua_block {
local ngx = require "ngx";
return ngx.redirect("/test?" .. ngx.var.args ,301)
}
}
也可以自定义参数,如下所示: return ngx.redirect("/test?test=1&a=2" ,301) 支持跳转到其他域名,如http://abc.testnginx.com: return ngx.redirect("http://abc.testnginx.com",301)
注意:跳转时都加return指令,其作用是为了强调跳转操作,官方推荐使用这种方式。
ngx.req.set_uri
语法:ngx.req.set_uri (uri, jump?)
配置环境:set_by_lua*,rewrite_by_lua*,access_by_lua*,content_by_lua*,header_filter_ by_lua*,body_filter_by_lua*
含义:用参数uri来重写当前的URL,和Nginx的rewrite内部重定向功能相似。例如,rewrite的指令rewrite ^ /test last; 与ngx.req.set_uri("/test", true)功能相似,而rewrite ^ /test break; 与ngx.req.set_uri("/foo", false)功能相似。 如果需要在跳转过程中修改参数,可以使用ngx.req.set_uri_args来完成新的参数配置,操作如下: ngx.req.set_uri_args("a=1&b=2&c=3") ngx.req.set_uri("/test", true) ngx.exec
语法:ngx.exec(uri, args?)
配置环境:rewrite_by_lua,access_by_lua*,content_by_lua*
含义:使用uri、args参数来完成内部重定向,类似于echo-nginx-module 的echo_exec指令。
示例:
server {
`listen 80;`
`server_name testnginx.com;`
`default_type 'text/plain';`
`location / {`
`content_by_lua_block {`
`return ngx.exec('/test');`
`}`
`}`
`location /test {`
`content_by_lua_block {`
`ngx.say(ngx.var.args);`
`}
}`
}
下面是ngx_exec指令常用的几种参数设置的示例。 保留之前的参数,如“ngx.exec('/test',ngx.var.args);”。 保留之前的参数,并新增参数,如“ngx.exec('/test' ,ngx.var.args .. 'd=4');”。 去掉之前的参数,并新增参数,如“ngx.exec('/test' , 'd=4');”。 注意:ngx_exec是一个内部重定向指令,不涉及外部的HTTP请求。在使用中推荐采用return ngx.exec(…)的方式。
在使用Lua进行开发的过程中,需要使用日志来输出异常和调试信息,在Lua API中可以使用ngx.log来记录日志。
语法:ngx.log(log_level, ...)
配置环境:init_by_lua*,init_worker_by_lua*,set_by_lua*,rewrite_by_lua*,access_by_ lua*,content_by_lua*,header_filter_by_lua*,body_filter_by_lua*,log_by_lua*,ngx.timer.,balancer_by_lua,ssl_certificate_by_lua*,ssl_session_fetch_by_lua*,ssl_session_store_by_lua*
含义:根据log_level的等级,将内容记录到error.log的日志文件中。 log_level的级别及其说明见表7-6(和Nginx的error.log日志级别是一致的)。 表7-6 log_level的级别及其说明
续表
示例:
server {
`listen 80;`
`server_name testnginx.com;`
`default_type 'text/plain';`
`location / {`
`content_by_lua_block {`
`ngx.say("test ")`
`ngx.say("nginx ")`
`ngx.log(ngx.ALERT, 'Log Test Nginx')`
`ngx.log(ngx.STDERR, 'Log Test Nginx')`
`ngx.log(ngx.EMERG, 'Log Test Nginx')`
`ngx.log(ngx.ALERT, 'Log Test Nginx')`
`ngx.log(ngx.CRIT, 'Log Test Nginx')`
`ngx.log(ngx.ERR, 'Log Test Nginx')`
`ngx.log(ngx.WARN, 'Log Test Nginx')`
`ngx.log(ngx.NOTICE, 'Log Test Nginx')`
`ngx.log(ngx.INFO, 'Log Test Nginx')`
`ngx.log(ngx.DEBUG, 'Log Test Nginx')`
`}`
`}`
}
执行结果如下:
curl -i 'http://testnginx.com/'
查看error.log 日志,默认在logs/error.log文件中,示例如下:
2018/06/11 11:18:26 [alert] 1180#1180: *34 [lua] content_by_lua (nginx.conf:66):4: Log Test Nginx, client:
10.19.48.161, server: testnginx.com, request: "GET / HTTP/1.1", host: "testnginx.com"
2018/06/11 11:18:26 [] 1180#1180: *34 [lua] content_by_lua (nginx.conf:66):5: Log Test Nginx, client:
10.19.48.161, server: testnginx.com, request: "GET / HTTP/1.1", host: "testnginx.com"
2018/06/11 11:18:26 [emerg] 1180#1180: *34 [lua] content_by_lua (nginx.conf:66):6: Log Test Nginx, client:
10.19.48.161, server: testnginx.com, request: "GET / HTTP/1.1", host: "testnginx.com"
2018/06/11 11:18:26 [alert] 1180#1180: *34 [lua] content_by_lua (nginx.conf:66):7: Log Test Nginx, client:
10.19.48.161, server: testnginx.com, request: "GET / HTTP/1.1", host: "testnginx.com"
2018/06/11 11:18:26 [crit] 1180#1180: *34 [lua] content_by_lua (nginx.conf:66):8: Log Test Nginx, client:
10.19.48.161, server: testnginx.com, request: "GET / HTTP/1.1", host: "testnginx.com"
2018/06/11 11:18:26 [error] 1180#1180: *34 [lua] content_by_lua (nginx.conf:66):9: Log Test Nginx, client:
10.19.48.161, server: testnginx.com, request: "GET / HTTP/1.1", host: "testnginx.com"
观察error.log日志可发现,它并没有输出所有级别的日志,这是因为Nginx中error.log的日志级别会影响Lua中日志的级别。如果将error.log的级别修改如下:
error_log /usr/local/nginx_1.12.2/logs/error.log info;
这样Lua的日志就可以打印到INFO级别了,如果需要DEBUG级别的日志,重新编译Nginx并开启DEBUG模式即可。 ngx.log支持多个字符串合并输出,字符串之间以逗号分隔,示例如下:
ngx.log(ngx.ERR, 'Log Test Nginx', 'a', 'b', 'c')
ngx.log单条日志可输出的最大字节数受Nginx的限制,默认最多是2048个字节,即2K。 Lua提供了print命令来简化INFO级别的日志的输出。下面两条语句的作用是一样的:
print("Log Test Nginx ")
ngx.log(ngx.INFO, 'Log Test Nginx')
注意:ngx.print 和print 是两条命令,不要混淆了。
在Lua中,可以对请求进行中断处理,有两种情况,如下:
- 中断整个请求,则请求不再继续执行,直接返回到客户端。
- 中断当前的执行阶段,请求会继续执行下一个阶段,并继续响应请求。
它们都是通过ngx.exit指令完成的。
语法:ngx.exit(status)
配置环境:rewrite_by_lua*,access_by_lua*,content_by_lua*,header_filter_by_lua*,ngx.timer.,balancer_by_lua,ssl_certificate_by_lua*,ssl_session_fetch_by_lua*,ssl_session_ store_by_lua*
含义:参数status的值是HTTP的状态码。当参数status>=200时,请求会被中断,并将status的值作为状态值返回给Nginx。 当参数status==0时,请求会中断当前的执行阶段,继续执行下一个阶段(前提是还有下一个阶段)。
配置环境:init_by_lua*,set_by_lua*,rewrite_by_lua*,access_by_lua*,content_by_ lua*,header_filter_by_lua*,body_filter_by_lua*,log_by_lua*,ngx.timer.,balancer_by_ lua,ssl_certificate_by_lua*,ssl_session_fetch_by_lua*,ssl_session_store_by_lua* Ngx_Lua HTTP状态码清单见表7-9。 表7-9 Ngx_Lua HTTP状态码清单
续表
下面是一个HTTP状态码为0的示例:
server {
`listen 80;`
`server_name testnginx.com;`
`default_type 'text/plain';`
`location / {`
`set $a '0';`
`rewrite_by_lua_block {`
`ngx.var.a = '1';`
`--等价于 ngx.exit(0), 0即HTTP状态码`
`ngx.exit(ngx.OK)`
`}`
`echo $a; #执行结果等于1 `
`}`
}
ngx.exit(ngx.OK)可以让Nginx退出当前的rewrite_by_lua_block阶段,继续执行下面的阶段,如上面代码中的echo。 如果想中断当前的请求,不再继续后面的执行阶段,可以设置两种退出状态: 设置状态码大于或等于200且小于300,表示成功退出当前请求。 设置状态码大于或等于500,或其他异常的状态,表示失败退出当前请求。 继续使用上面的例子,这次以非0的状态码退出当前请求,如下所示:
location / {
`set $a '0'; `
`rewrite_by_lua_block {`
`ngx.var.a = '1';`
`ngx.exit(200) --也可以换成500,数字代表状态码的值`
`}`
`echo $a; #没有执行到这一句`
}
因为使用了200状态码,所以请求在ngx.exit处被中断后退出了,所以无法执行echo输出的命令。为了强调退出操作,可以在此命令前加上return,如下
所示:
return ngx.exit(ngx.OK)