一、前言:为什么你需要 OpenResty?
你是否遇到过这些痛点?
- ❌ 业务逻辑必须放在后端,Nginx 只能做简单转发
- ❌ 鉴权、限流、日志等通用功能重复开发
- ❌ 高并发下后端压力大,响应慢
OpenResty = Nginx + LuaJIT ,让你在 Nginx 层直接编写业务逻辑 ,实现:
✅ 毫秒级响应
✅ 百万 QPS 承载能力
✅ 统一网关控制(鉴权、限流、日志、灰度)
本文将带你10 分钟快速上手 OpenResty,从配置到写第一个 Lua 脚本!
二、OpenResty 核心优势
| 能力 | 说明 |
|---|---|
| 🚀 高性能 | 基于 Nginx 事件驱动 + LuaJIT JIT 编译 |
| 💡 可编程 | 在 Nginx 配置中嵌入 Lua 代码 |
| 🔌 丰富生态 | 内置 Redis、MySQL、HTTP 客户端 |
| 🛡️ 企业级应用 | 被阿里、腾讯、360、Kong 等广泛使用 |
💡 一句话理解:OpenResty 让 Nginx 从"静态代理"变成"动态网关"。
三、OpenResty 请求处理阶段(关键!)
OpenResty 在 Nginx 的基础上扩展了多个 Lua 执行阶段,最常用的是:
XML
server {
location /test {
# 1. 初始化(全局)
init_by_lua_block { ... }
# 2. 重写阶段(改写 URI/参数)
rewrite_by_lua_block { ... }
# 3. 访问阶段(核心逻辑)
access_by_lua_block { ... }
# 4. 内容生成阶段(返回响应)
content_by_lua_block { ... }
# 5. 日志阶段
log_by_lua_block { ... }
}
}
✅ 新手重点掌握 :
access_by_lua_block(鉴权/限流)和content_by_lua_block(返回数据)
四、实战 1:Hello World!
4.1 修改配置文件
编辑 /usr/local/openresty/nginx/conf/nginx.conf(或 /etc/openresty/nginx.conf):
XML
server {
listen 80;
server_name localhost;
location /hello {
default_type 'text/plain';
content_by_lua_block {
ngx.say("Hello, OpenResty!")
ngx.say("Current time: ", ngx.now())
}
}
}
4.2 重载配置 & 测试
bash
# 重载配置(不中断服务)
sudo openresty -s reload
# 测试
curl http://localhost/hello
输出:
Hello, OpenResty!
Current time: 1730123456.789
🎉 恭喜!你已成功运行第一个 OpenResty 脚本!
五、实战 2:实现 IP 黑名单(access 阶段)
bash
location /api/ {
access_by_lua_block {
local black_ips = {
["192.168.1.100"] = true,
["10.0.0.5"] = true
}
local client_ip = ngx.var.remote_addr
if black_ips[client_ip] then
ngx.log(ngx.WARN, "Blocked IP: ", client_ip)
ngx.exit(403) -- 直接返回 403
end
-- 继续后续处理(如反向代理)
}
# 反向代理到后端
proxy_pass http://backend;
}
✅ 优势 :在 Nginx 层拦截恶意请求,不消耗后端资源!
六、实战 3:调用 Redis 实现限流
6.1 安装 lua-resty-redis(通常已内置)
OpenResty 默认包含 resty.redis 模块。
6.2 限流脚本(每秒最多 5 次)
bash
location /limited {
access_by_lua_block {
local redis = require "resty.redis"
local red = redis:new()
red:set_timeout(1000) -- 1s 超时
local ok, err = red:connect("127.0.0.1", 6379)
if not ok then
ngx.log(ngx.ERR, "Redis connect failed: ", err)
ngx.exit(500)
end
local key = "rate_limit:" .. ngx.var.remote_addr
local requests = red:get(key)
if not requests or requests == ngx.null then
red:set(key, 1)
red:expire(key, 1) -- 1秒过期
elseif tonumber(requests) >= 5 then
ngx.log(ngx.WARN, "Rate limit exceeded for ", ngx.var.remote_addr)
ngx.exit(429)
else
red:incr(key)
end
red:close()
}
content_by_lua_block {
ngx.say("Request allowed!")
}
}
🔥 效果:单 IP 每秒最多 5 次请求,超限返回 429。
七、常用 Lua 模块与 API
| 模块/变量 | 用途 |
|---|---|
ngx.var.remote_addr |
客户端 IP |
ngx.req.get_headers() |
获取请求头 |
ngx.req.read_body() + ngx.req.get_post_args() |
获取 POST 参数 |
ngx.redirect(url) |
重定向 |
ngx.print() / ngx.say() |
输出响应 |
ngx.exit(code) |
终止请求并返回状态码 |
require "resty.redis" |
Redis 客户端 |
require "resty.http" |
HTTP 客户端 |
八、调试技巧
8.1 查看日志
bash
# 错误日志
tail -f /usr/local/openresty/nginx/logs/error.log
# 访问日志(需配置 log_by_lua_block)
8.2 打印调试信息
Lua
ngx.log(ngx.INFO, "Debug: user_id=", user_id)
⚠️ 注意:生产环境避免打印敏感信息!
九、最佳实践建议
✅ 轻量逻辑 :Lua 脚本执行时间 < 10ms,避免阻塞 Nginx
✅ 连接池 :使用 resty.redis 的连接池(set_keepalive)
✅ 错误处理 :始终检查 ok, err = ...
✅ 配置分离 :复杂逻辑抽离为 .lua 文件,用 content_by_lua_file 引入
Lua
location /complex {
content_by_lua_file /etc/openresty/lua/my_logic.lua;
}
十、结语
感谢您的阅读!如果你有任何疑问或想要分享的经验,请在评论区留言交流!