OpenResty #
一、OpenResty 简介 #
1.1 什么是 OpenResty #
OpenResty 是一个基于 Nginx 与 Lua 的高性能 Web 平台,由章亦春开发。它将 Nginx 核心与许多 Lua 库集成在一起,使得开发者能够使用 Lua 脚本调动 Nginx 支持的各种模块。
1.2 核心特点 #
- 高性能:基于 Nginx 事件模型
- 非阻塞 I/O:所有操作都是异步的
- 轻量级:内存占用低,并发能力强
- 可编程:使用 Lua 扩展 Nginx 功能
1.3 应用场景 #
- API 网关(如 Kong)
- Web 应用防火墙(WAF)
- 负载均衡
- 动态路由
- 缓存服务
二、安装与配置 #
2.1 安装 OpenResty #
bash
# macOS
brew install openresty/brew/openresty
# Ubuntu
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
sudo yum install -y openresty
2.2 基本配置 #
nginx
# nginx.conf
worker_processes auto;
error_log logs/error.log info;
events {
worker_connections 1024;
}
http {
lua_package_path "/usr/local/openresty/lualib/?.lua;;";
lua_package_cpath "/usr/local/openresty/lualib/?.so;;";
server {
listen 8080;
location / {
default_type text/html;
content_by_lua_block {
ngx.say("Hello, OpenResty!")
}
}
}
}
2.3 启动服务 #
bash
# 启动
openresty
# 重启
openresty -s reload
# 停止
openresty -s stop
# 测试配置
openresty -t
三、基本用法 #
3.1 content_by_lua_block #
nginx
location /hello {
content_by_lua_block {
ngx.say("Hello, World!")
ngx.say("当前时间:", ngx.now())
}
}
3.2 处理请求参数 #
nginx
location /api {
content_by_lua_block {
local args = ngx.req.get_uri_args()
local name = args.name or "World"
ngx.say("Hello, ", name, "!")
}
}
3.3 处理 POST 请求 #
nginx
location /submit {
methods POST;
content_by_lua_block {
ngx.req.read_body()
local data = ngx.req.get_body_data()
if not data then
ngx.status = 400
ngx.say("缺少请求体")
return ngx.exit(400)
end
ngx.say("收到数据:", data)
}
}
3.4 返回 JSON #
nginx
location /json {
content_by_lua_block {
local cjson = require "cjson"
local response = {
status = "success",
data = {
name = "OpenResty",
version = "1.21.4"
}
}
ngx.header["Content-Type"] = "application/json"
ngx.say(cjson.encode(response))
}
}
四、访问数据库 #
4.1 连接 MySQL #
lua
local mysql = require "resty.mysql"
local db, err = mysql:new()
if not db then
ngx.log(ngx.ERR, "failed to instantiate mysql: ", err)
return ngx.exit(500)
end
db:set_timeout(1000) -- 1 秒超时
local ok, err, errcode, sqlstate = db:connect{
host = "127.0.0.1",
port = 3306,
database = "test",
user = "root",
password = "password",
charset = "utf8mb4"
}
if not ok then
ngx.log(ngx.ERR, "failed to connect: ", err)
return ngx.exit(500)
end
-- 执行查询
local res, err, errcode, sqlstate = db:query("SELECT * FROM users LIMIT 10")
if not res then
ngx.log(ngx.ERR, "bad result: ", err)
return ngx.exit(500)
end
local cjson = require "cjson"
ngx.say(cjson.encode(res))
-- 关闭连接
db:close()
4.2 连接 Redis #
lua
local redis = require "resty.redis"
local red = redis:new()
red:set_timeout(1000)
local ok, err = red:connect("127.0.0.1", 6379)
if not ok then
ngx.log(ngx.ERR, "failed to connect: ", err)
return ngx.exit(500)
end
-- 设置值
local ok, err = red:set("key", "value")
if not ok then
ngx.log(ngx.ERR, "failed to set: ", err)
end
-- 获取值
local res, err = red:get("key")
ngx.say("value: ", res)
-- 放回连接池
red:set_keepalive(10000, 100)
五、HTTP 请求 #
5.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.say("请求失败")
end
}
}
location /api/data {
content_by_lua_block {
ngx.say("内部数据")
}
}
5.2 外部 HTTP 请求 #
lua
local http = require "resty.http"
local httpc = http.new()
local res, err = httpc:request_uri("https://api.example.com/data", {
method = "GET",
headers = {
["Content-Type"] = "application/json"
}
})
if not res then
ngx.log(ngx.ERR, "request failed: ", err)
return ngx.exit(500)
end
ngx.say(res.body)
六、缓存 #
6.1 共享内存缓存 #
nginx
http {
lua_shared_dict cache 10m;
server {
location /cache {
content_by_lua_block {
local cache = ngx.shared.cache
-- 设置缓存
cache:set("key", "value", 60) -- 60秒过期
-- 获取缓存
local value = cache:get("key")
ngx.say("value: ", value)
}
}
}
}
6.2 LRU 缓存 #
lua
local lrucache = require "resty.lrucache"
local cache, err = lrucache.new(200) -- 最多缓存200个对象
if not cache then
ngx.log(ngx.ERR, "failed to create cache: ", err)
return
end
-- 设置缓存
cache:set("key", "value", 60)
-- 获取缓存
local value = cache:get("key")
ngx.say("value: ", value)
七、API 网关示例 #
7.1 认证中间件 #
lua
-- auth.lua
local _M = {}
function _M.check_token()
local token = ngx.req.get_headers()["Authorization"]
if not token then
ngx.status = 401
ngx.say('{"error": "Missing token"}')
return ngx.exit(401)
end
-- 验证 token
local redis = require "resty.redis"
local red = redis:new()
red:connect("127.0.0.1", 6379)
local user_id = red:get("token:" .. token)
if not user_id or user_id == ngx.null then
ngx.status = 401
ngx.say('{"error": "Invalid token"}')
return ngx.exit(401)
end
-- 设置用户信息
ngx.ctx.user_id = user_id
end
return _M
7.2 限流 #
lua
local limit_req = require "resty.limit.req"
local lim, err = limit_req.new("my_limit_req_store", 10, 5)
if not lim then
ngx.log(ngx.ERR, "failed to instantiate a resty.limit.req object: ", err)
return ngx.exit(500)
end
local key = ngx.var.binary_remote_addr
local delay, err = lim:incoming(key, true)
if not delay then
if err == "rejected" then
ngx.status = 429
ngx.say('{"error": "Too many requests"}')
return ngx.exit(429)
end
ngx.log(ngx.ERR, "failed to limit req: ", err)
return ngx.exit(500)
end
if delay >= 0.001 then
ngx.sleep(delay)
end
八、最佳实践 #
8.1 使用连接池 #
lua
-- 放回连接池而不是关闭
red:set_keepalive(10000, 100) -- 最大空闲时间10秒,连接池大小100
8.2 错误处理 #
lua
local ok, err = pcall(function()
-- 可能出错的代码
end)
if not ok then
ngx.log(ngx.ERR, "error: ", err)
ngx.status = 500
ngx.say('{"error": "Internal server error"}')
return ngx.exit(500)
end
8.3 使用模块组织代码 #
lua
-- myapp/utils.lua
local _M = {}
function _M.json_response(data)
local cjson = require "cjson"
ngx.header["Content-Type"] = "application/json"
ngx.say(cjson.encode(data))
end
return _M
九、总结 #
OpenResty 是构建高性能 Web 应用的强大平台:
- 高性能:基于 Nginx 事件模型
- 异步 I/O:非阻塞操作
- 丰富库:数据库、缓存、HTTP 客户端
- 应用广泛:API 网关、WAF、负载均衡
下一章,我们将学习 LÖVE 游戏引擎。
最后更新:2026-03-27