Nginx Lua扩展 #
一、OpenResty概述 #
1.1 什么是OpenResty #
OpenResty是一个基于Nginx的Web平台,集成了大量精良的Lua库,使得Nginx可以作为一个强大的Web应用服务器。
1.2 OpenResty特点 #
- 基于Nginx
- 内置LuaJIT
- 丰富的Lua库
- 非阻塞I/O
- 高性能
1.3 安装OpenResty #
Ubuntu/Debian:
bash
wget -qO - https://openresty.org/package/pubkey.gpg | sudo apt-key add -
sudo apt-get -y install software-properties-common
sudo add-apt-repository -y "deb http://openresty.org/package/ubuntu $(lsb_release -sc) main"
sudo apt-get update
sudo apt-get install -y openresty
CentOS/RHEL:
bash
sudo yum install -y yum-utils
sudo yum-config-manager --add-repo https://openresty.org/package/centos/openresty.repo
sudo yum install -y openresty
Docker:
bash
docker pull openresty/openresty
二、基本Lua脚本 #
2.1 Hello World #
nginx
location /hello {
default_type text/html;
content_by_lua_block {
ngx.say("Hello, OpenResty!")
}
}
2.2 外部Lua文件 #
nginx
location /hello {
default_type text/html;
content_by_lua_file /path/to/hello.lua;
}
hello.lua:
lua
ngx.say("Hello from external file!")
2.3 Lua代码位置 #
| 指令 | 执行阶段 |
|---|---|
| init_by_lua | Nginx初始化 |
| init_worker_by_lua | Worker初始化 |
| set_by_lua | 设置变量 |
| rewrite_by_lua | 重写阶段 |
| access_by_lua | 访问控制 |
| content_by_lua | 内容生成 |
| header_filter_by_lua | 响应头过滤 |
| body_filter_by_lua | 响应体过滤 |
| log_by_lua | 日志阶段 |
三、ngx库 #
3.1 输出内容 #
nginx
location /output {
content_by_lua_block {
ngx.say("Hello")
ngx.print("World")
ngx.exit(200)
}
}
3.2 获取请求信息 #
nginx
location /request {
content_by_lua_block {
ngx.say("Method: ", ngx.req.get_method())
ngx.say("URI: ", ngx.var.uri)
ngx.say("Args: ", ngx.var.args)
ngx.say("Host: ", ngx.var.host)
ngx.say("Remote Addr: ", ngx.var.remote_addr)
ngx.say("User Agent: ", ngx.var.http_user_agent)
}
}
3.3 获取请求参数 #
nginx
location /args {
content_by_lua_block {
local args = ngx.req.get_uri_args()
for k, v in pairs(args) do
ngx.say(k, ": ", v)
end
}
}
3.4 获取请求体 #
nginx
location /body {
content_by_lua_block {
ngx.req.read_body()
local body = ngx.req.get_body_data()
ngx.say("Body: ", body)
}
}
3.5 获取请求头 #
nginx
location /headers {
content_by_lua_block {
local headers = ngx.req.get_headers()
for k, v in pairs(headers) do
ngx.say(k, ": ", v)
end
}
}
四、响应操作 #
4.1 设置响应头 #
nginx
location /set_header {
content_by_lua_block {
ngx.header["X-Custom-Header"] = "Custom Value"
ngx.header["Content-Type"] = "application/json"
ngx.say('{"status": "ok"}')
}
}
4.2 设置状态码 #
nginx
location /status {
content_by_lua_block {
ngx.status = 201
ngx.say("Created")
}
}
4.3 重定向 #
nginx
location /redirect {
content_by_lua_block {
ngx.redirect("https://example.com", 301)
}
}
五、访问控制 #
5.1 IP白名单 #
nginx
location /admin {
access_by_lua_block {
local ip = ngx.var.remote_addr
local whitelist = {
"192.168.1.0/24",
"10.0.0.0/8"
}
local function ip_in_cidr(ip, cidr)
-- 实现CIDR匹配
return true
end
local allowed = false
for _, cidr in ipairs(whitelist) do
if ip_in_cidr(ip, cidr) then
allowed = true
break
end
end
if not allowed then
ngx.exit(403)
end
}
proxy_pass http://backend;
}
5.2 JWT验证 #
nginx
location /api {
access_by_lua_block {
local jwt = require "resty.jwt"
local token = ngx.var.http_authorization
if not token then
ngx.exit(401)
end
local jwt_obj = jwt:verify("secret_key", token)
if not jwt_obj.verified then
ngx.exit(401)
end
ngx.req.set_header("X-User-ID", jwt_obj.payload.sub)
}
proxy_pass http://backend;
}
5.3 请求签名验证 #
nginx
location /api {
access_by_lua_block {
local resty_hmac = require "resty.hmac"
local timestamp = ngx.var.http_x_timestamp
local signature = ngx.var.http_x_signature
local secret = "your_secret_key"
local hmac = resty_hmac:new(secret, resty_hmac.ALGOS.SHA256)
local expected = hmac:final(timestamp)
if signature ~= expected then
ngx.exit(401)
end
}
proxy_pass http://backend;
}
六、动态配置 #
6.1 共享内存 #
nginx
lua_shared_dict config 10m;
location /config {
content_by_lua_block {
local config = ngx.shared.config
config:set("api_key", "12345")
local value = config:get("api_key")
ngx.say("API Key: ", value)
}
}
6.2 动态upstream #
nginx
lua_shared_dict upstreams 10m;
init_worker_by_lua_block {
local upstreams = ngx.shared.upstreams
upstreams:set("backend1", "192.168.1.10:8080")
upstreams:set("backend2", "192.168.1.11:8080")
}
location / {
content_by_lua_block {
local upstreams = ngx.shared.upstreams
local server = upstreams:get("backend1")
local res = ngx.location.capture("/proxy/" .. server .. ngx.var.uri)
ngx.say(res.body)
}
}
6.3 配置热更新 #
nginx
lua_shared_dict dynamic_config 10m;
location /admin/reload {
content_by_lua_block {
local config = ngx.shared.dynamic_config
local new_config = ngx.req.get_body_data()
config:set("rules", new_config)
ngx.say("Config reloaded")
}
}
七、数据库访问 #
7.1 MySQL #
nginx
location /mysql {
content_by_lua_block {
local mysql = require "resty.mysql"
local db, err = mysql:new()
db:set_timeout(1000)
local ok, err, errcode, sqlstate = db:connect{
host = "127.0.0.1",
port = 3306,
database = "test",
user = "root",
password = "password"
}
local res, err, errcode, sqlstate = db:query("SELECT * FROM users")
local cjson = require "cjson"
ngx.say(cjson.encode(res))
db:close()
}
}
7.2 Redis #
nginx
location /redis {
content_by_lua_block {
local redis = require "resty.redis"
local red = redis:new()
red:set_timeout(1000)
local ok, err = red:connect("127.0.0.1", 6379)
local res, err = red:get("key")
ngx.say("Value: ", res)
red:close()
}
}
7.3 连接池 #
nginx
location /redis {
content_by_lua_block {
local redis = require "resty.redis"
local red = redis:new()
red:connect("127.0.0.1", 6379)
local res, err = red:get("key")
ngx.say(res)
red:set_keepalive(10000, 100)
}
}
八、HTTP请求 #
8.1 内部请求 #
nginx
location /internal {
content_by_lua_block {
local res = ngx.location.capture("/api/data")
if res.status == 200 then
ngx.say(res.body)
else
ngx.exit(res.status)
end
}
}
location /api/data {
internal;
proxy_pass http://backend;
}
8.2 外部请求 #
nginx
location /external {
content_by_lua_block {
local http = require "resty.http"
local httpc = http.new()
local res, err = httpc:request_uri("http://example.com/api", {
method = "GET",
headers = {
["Content-Type"] = "application/json"
}
})
if res then
ngx.say(res.body)
end
}
}
九、API网关示例 #
9.1 完整网关配置 #
nginx
lua_shared_dict api_cache 10m;
lua_shared_dict rate_limit 10m;
init_by_lua_block {
local api_config = {
["/api/user"] = {
upstream = "user-service",
rate_limit = 100,
auth = true
},
["/api/order"] = {
upstream = "order-service",
rate_limit = 50,
auth = true
},
["/api/public"] = {
upstream = "public-service",
rate_limit = 200,
auth = false
}
}
package.loaded.api_config = api_config
}
server {
listen 80;
location /api {
access_by_lua_block {
local api_config = package.loaded.api_config
local path = ngx.var.uri
local config = api_config[path]
if not config then
ngx.exit(404)
end
if config.auth then
local token = ngx.var.http_authorization
if not token then
ngx.exit(401)
end
local jwt = require "resty.jwt"
local jwt_obj = jwt:verify("secret", token)
if not jwt_obj.verified then
ngx.exit(401)
end
end
local rate_limit = ngx.shared.rate_limit
local key = ngx.var.remote_addr .. ":" .. path
local count = rate_limit:incr(key, 1, 0, 60)
if count > config.rate_limit then
ngx.exit(429)
end
}
content_by_lua_block {
local api_config = package.loaded.api_config
local config = api_config[ngx.var.uri]
local res = ngx.location.capture("/proxy/" .. config.upstream .. ngx.var.request_uri)
ngx.status = res.status
for k, v in pairs(res.header) do
ngx.header[k] = v
end
ngx.say(res.body)
}
}
location ~ ^/proxy/([^/]+)(.*) {
internal;
set $upstream $1;
set $path $2;
proxy_pass http://$upstream$path;
}
}
十、性能优化 #
10.1 Lua代码缓存 #
nginx
lua_code_cache on;
生产环境必须开启。
10.2 JIT优化 #
nginx
lua_jit_enable on;
10.3 共享内存 #
nginx
lua_shared_dict cache 100m;
10.4 连接池 #
lua
local ok, err = red:set_keepalive(10000, 100)
十一、调试技巧 #
11.1 日志输出 #
lua
ngx.log(ngx.ERR, "Error message")
ngx.log(ngx.WARN, "Warning message")
ngx.log(ngx.INFO, "Info message")
ngx.log(ngx.DEBUG, "Debug message")
11.2 调试模式 #
nginx
lua_code_cache off;
error_log logs/error.log debug;
十二、总结 #
本章我们学习了:
- OpenResty基础:安装和基本概念
- Lua脚本:基本语法和ngx库
- 请求处理:获取参数、请求体、请求头
- 响应操作:设置头、状态码、重定向
- 访问控制:IP白名单、JWT验证、签名验证
- 动态配置:共享内存、动态upstream
- 数据库访问:MySQL、Redis、连接池
- HTTP请求:内部请求和外部请求
- API网关:完整网关实现
- 性能优化:代码缓存、JIT、连接池
掌握Lua扩展后,让我们进入下一章,学习健康检查!
最后更新:2026-03-27