nginx+lua
lua语言
1. lua发展史
Lua 从一开始就是作为一门方便嵌入(其它应用程序)并可扩展的轻量级脚本语言来设计的,因此她一直遵从着简单、小巧、可移植、快速的原则,官方实现完全采用 ANSI C 编写,能以 C 程序库的形式嵌入到宿主程序中。LuaJIT 2 和标准 Lua 5.1 解释器采用的是著名的 MIT 许可协议。正由于上述特点,所以 Lua 在游戏开发、机器人控制、分布式应用、图像处理、生物信息学等各种各样的领域中得到了越来越广泛的应用。其中尤以游戏开发为最,许多著名的游戏,比如 Escape from Monkey Island、World of Warcraft、大话西游,都采用了 Lua 来配合引擎完成数据描述、配置管理和逻辑控制等任务。即使像 Redis 这样中性的内存键值数据库也提供了内嵌用户 Lua 脚本的官方支持。
作为一门过程型动态语言,Lua 有着如下的特性:
变量名没有类型,值才有类型,变量名在运行时可与任何类型的值绑定;
语言只提供唯一一种数据结构,称为表(table),它混合了数组、哈希,可以用任何类型的值作为 key 和 value。提供了一致且富有表达力的表构造语法,使得 Lua 很适合描述复杂的数据;
函数是一等类型,支持匿名函数和正则尾递归(proper tail recursion);
支持词法定界(lexical scoping)和闭包(closure);
提供 thread 类型和结构化的协程(coroutine)机制,在此基础上可方便实现协作式多任务;
运行期能编译字符串形式的程序文本并载入虚拟机执行;
通过元表(metatable)和元方法(metamethod)提供动态元机制(dynamic meta-mechanism),从而允许程序运行时根据需要改变或扩充语法设施的内定语义;
能方便地利用表和动态元机制实现基于原型(prototype-based)的面向对象模型;
从 5.1 版开始提供了完善的模块机制,从而更好地支持开发大型的应用程序;
2. Lua 和 LuaJIT 的区别
Lua 非常高效,它运行得比许多其它脚本(如 Perl、Python、Ruby)都快,这点在第三方的独立测评中得到了证实。尽管如此,仍然会有人不满足,他们总觉得“嗯,还不够快!”。LuaJIT 就是一个为了再榨出一些速度的尝试,它利用即时编译(Just-in Time)技术把 Lua 代码编译成本地机器码后交由 CPU 直接执行。LuaJIT 2 的测评报告表明,在数值运算、循环与函数调用、协程切换、字符串操作等许多方面它的加速效果都很显著。凭借着 FFI 特性,LuaJIT 2 在那些需要频繁地调用外部 C/C++ 代码的场景,也要比标准 Lua 解释器快很多。目前 LuaJIT 2 已经支持包括 i386、x86_64、ARM、PowerPC 以及 MIPS 等多种不同的体系结构。+
LuaJIT 是采用 C 和汇编语言编写的 Lua 解释器与即时编译器。LuaJIT 被设计成全兼容标准的 Lua 5.1 语言,同时可选地支持 Lua 5.2 和 Lua 5.3 中的一些不破坏向后兼容性的有用特性。因此,标准 Lua 语言的代码可以不加修改地运行在 LuaJIT 之上。LuaJIT 和标准 Lua 解释器的一大区别是,LuaJIT 的执行速度,即使是其汇编编写的 Lua 解释器,也要比标准 Lua 5.1 解释器快很多,可以说是一个高效的 Lua 实现。另一个区别是,LuaJIT 支持比标准 Lua 5.1 语言更多的基本原语和特性,因此功能上也要更加强大。
若无特殊说明,我们接下来的章节都是基于 LuaJIT 进行介绍的。
Lua 官网链接:http://www.lua.org
LuaJIT 官网链接:http://luajit.org
nginx_lua模块基本使用
nginx流程
Nginx 处理请求的过程一共划分为 11 个阶段,按照执行顺序依次是 post-read、server-rewrite、find-config、rewrite、post-rewrite、preaccess、access、post-access、try-files、content 以及 log.
Nginx 的请求处理阶段共有 11 个之多,我们先介绍其中 3 个比较常见的。按照它们执行时的先后顺序,依次是 rewrite 阶段、access 阶段以及 content 阶段(后面我们还有机会见到其他更多的处理阶段)。
所有 Nginx 模块提供的配置指令一般只会注册并运行在其中的某一个处理阶段。比如上例中的 set 指令就是在 rewrite 阶段运行的,而 echo 指令就只会在 content 阶段运行。前面我们已经知道,在单个请求的处理过程中,rewrite 阶段总是在 content 阶段之前执行,因此属于 rewrite 阶段的配置指令也总是会无条件地在 content 阶段的配置指令之前执行。于是在同一个 location 配置块中,set 指令总是会在 echo 指令之前执行,即使我们在配置文件中 有意把 set 语句写在 echo 语句的后面。
lua的执行顺序:
第三方模块 ngx_lua 提供的 rewrite_by_lua 配置指令也和 more_set_input_headers 一样运行在 rewrite 阶段的末尾。
在 rewrite 阶段之后,有一个名叫 access 的请求处理阶段。
ngx_lua 模块提供了配置指令 access_by_lua,用于在 access 请求处理阶段插入用户 Lua 代码。这条指令运行于 access 阶段的末尾,因此总是在 allow 和 deny 这样的指令之后运行,虽然它们同属 access 阶段。一般我们通过 access_by_lua 在 ngx_access 这样的模块检查过客户端 IP 地址之后,再通过 Lua 代码执行一系列更为复杂的请求验证操作,比如实时查询数据库或者其他后端服务,以验证当前用户的身份或权限。
我们来看一个简单的例子,利用 access_by_lua 来实现 ngx_access 模块的 IP 地址过滤功能:
location /hello {
access_by_lua '
if ngx.var.remote_addr == "127.0.0.1" then
return
end
ngx.exit(403)
';
echo "hello world";
}
使用 ngx_access 模块的例子:
location /hello {
allow 127.0.0.1;
deny all;
echo "hello world";
}
虽然这两个例子在功能上完全相同,但在性能上还是有区别的,毕竟 ngx_access 是用纯 C 实现的专门化的 Nginx 模块。
进一步地,在 rewrite 和 access 这两个阶段,多个模块的配置指令可以同时使用,譬如上例中的 set 指令和 rewrite_by_lua 指令同处 rewrite 阶段,而 deny 指令和 access_by_lua 指令则同处 access 阶段。但不幸的是,这通常不适用于 content 阶段。
绝大多数 Nginx 模块在向 content 阶段注册配置指令时,本质上是在当前的 location 配置块中注册所谓的“内容处理程序”(content handler)。每一个 location 只能有一个“内容处理程序”,因此,当在 location 中同时使用多个模块的 content 阶段指令时,只有其中一个模块能成功注册“内容处理程序”。考虑下面这个有问题的例子:
? location /test {
? echo hello;
? content_by_lua 'ngx.say("world")';
? }
这里,ngx_echo 模块的 echo 指令和 ngx_lua 模块的 content_by_lua 指令同处 content 阶段,于是只有其中一个模块能注册和运行这个 location 的“内容处理程序”:
$ curl ‘http://localhost:8080/test’
world
实际运行结果表明,写在后面的 content_by_lua 指令反而胜出了,而 echo 指令则完全没有运行。具体哪一个模块的指令会胜出是不确定的,例如把上例中的 echo 语句和 content_by_lua 语句交换顺序,则输出就会变成 hello,即 ngx_echo 模块胜出。所以我们应当避免在同一个 location 中使用多个模块的 content 阶段指令。
将上例中的 content_by_lua 指令替换为 echo 指令就可以如愿了:
location /test {
echo hello;
echo world;
}
测试结果证明了这一点:
$ curl ‘http://localhost:8080/test’
hello
world
http://blog.sina.com.cn/s/blog_6d579ff40100xm7t.html
使用语法 http://blog.csdn.net/joeyon1985/article/details/46744805
openresty使用,香草
https://moonbingbing.gitbooks.io/openresty-best-practices/content/lua/dummy_var.html