第7章 - OpenResty 入门
嗨,朋友!我是长安。
这一章我们来了解 OpenResty——一个基于 Nginx + Lua 的高性能 Web 平台。很多互联网公司用它来做 API 网关、WAF(Web 应用防火墙)、动态路由等。
🤔 OpenResty 是什么?
简单来说:OpenResty = Nginx + LuaJIT + 一堆好用的 Lua 库
| 特性 | 说明 |
|---|---|
| 基于 Nginx | 继承了 Nginx 的高性能和高并发能力 |
| 内嵌 LuaJIT | 在 Nginx 中直接运行 Lua 代码 |
| 非阻塞 I/O | Lua 代码也是非阻塞的,不会降低 Nginx 性能 |
| 丰富的库 | HTTP 客户端、Redis 客户端、MySQL 客户端等 |
为什么 Java 程序员要了解它?
- API 网关 — 很多公司用 OpenResty 做网关,Java 服务在后面
- 限流/鉴权 — 在 Nginx 层做限流和鉴权,减轻后端压力
- 灰度发布 — 用 Lua 脚本控制流量分发
- 动态路由 — 根据请求参数动态选择后端服务
OpenResty (Nginx + Lua)
┌────────────────────┐
用户请求 ──────────►│ 限流 │ 鉴权 │ 路由 │
└────────┬───────────┘
│
┌────────┼───────────┐
▼ ▼ ▼
SpringBoot SpringBoot SpringBoot
服务 A 服务 B 服务 C
🚀 安装 OpenResty
macOS
brew install openresty/brew/openresty
Linux (Ubuntu)
# 添加 APT 仓库
wget -qO - https://openresty.org/package/pubkey.gpg | sudo apt-key add -
sudo apt-get install -y 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
Windows
从 OpenResty 官网 下载 Windows 版本。
验证安装
openresty -v
# nginx version: openresty/1.25.x.x
📖 Hello World
项目结构
my-openresty/
├── conf/
│ └── nginx.conf
├── logs/
└── lua/
└── hello.lua
nginx.conf
worker_processes 1;
error_log logs/error.log;
events {
worker_connections 1024;
}
http {
server {
listen 8080;
# 直接在配置中写 Lua
location /hello {
content_by_lua_block {
ngx.say("Hello, OpenResty!")
}
}
# 引用外部 Lua 文件
location /api {
content_by_lua_file lua/hello.lua;
}
}
}
lua/hello.lua
-- 获取请求参数
local args = ngx.req.get_uri_args()
local name = args.name or "World"
-- 设置响应头
ngx.header["Content-Type"] = "application/json"
-- 返回 JSON 响应
local cjson = require("cjson")
local response = {
message = "Hello, " .. name .. "!",
method = ngx.req.get_method(),
uri = ngx.var.uri,
time = ngx.now()
}
ngx.say(cjson.encode(response))
启动和测试
# 启动
openresty -p /path/to/my-openresty/
# 测试
curl http://localhost:8080/hello
# Hello, OpenResty!
curl "http://localhost:8080/api?name=长安"
# {"message":"Hello, 长安!","method":"GET","uri":"/api","time":1706000000}
🔧 Nginx Lua 执行阶段
OpenResty 的 Lua 代码在 Nginx 的不同处理阶段执行:
| 指令 | 阶段 | 用途 |
|---|---|---|
init_by_lua | 启动时 | 加载全局配置 |
init_worker_by_lua | Worker 启动时 | 初始化定时器 |
set_by_lua | rewrite 阶段 | 设置变量 |
rewrite_by_lua | rewrite 阶段 | URL 重写 |
access_by_lua | access 阶段 | 鉴权、限流 |
content_by_lua | content 阶段 | 生成响应 |
header_filter_by_lua | 响应头阶段 | 修改响应头 |
body_filter_by_lua | 响应体阶段 | 修改响应体 |
log_by_lua | log 阶段 | 自定义日志 |
🌟 实战:API 限流
-- lua/rate_limit.lua
-- 基于令牌桶的接口限流
local limit_count = ngx.shared.limit_count -- 需要在 nginx.conf 中声明共享内存
local function rate_limit(key, limit, window)
local count, err = limit_count:get(key)
if not count then
-- 第一次请求
limit_count:set(key, 1, window)
return true
end
if count >= limit then
return false -- 超过限制
end
limit_count:incr(key, 1)
return true
end
-- 获取客户端 IP
local client_ip = ngx.var.remote_addr
local key = "rate:" .. client_ip
-- 每秒最多 10 次请求
if not rate_limit(key, 10, 1) then
ngx.status = 429
ngx.say('{"error": "Too Many Requests"}')
return ngx.exit(429)
end
-- 通过限流,继续处理...
# nginx.conf 中声明共享内存
http {
lua_shared_dict limit_count 10m;
server {
listen 8080;
location /api/ {
access_by_lua_file lua/rate_limit.lua;
proxy_pass http://backend;
}
}
}
🌟 实战:JWT 鉴权
-- lua/auth.lua
-- JWT Token 验证
local cjson = require("cjson")
-- 获取 Authorization 头
local auth_header = ngx.req.get_headers()["Authorization"]
if not auth_header then
ngx.status = 401
ngx.say('{"error": "Missing Authorization header"}')
return ngx.exit(401)
end
-- 提取 Token
local token = auth_header:match("Bearer%s+(.+)")
if not token then
ngx.status = 401
ngx.say('{"error": "Invalid token format"}')
return ngx.exit(401)
end
-- 简单的 Token 验证(实际项目中应该验证 JWT 签名)
-- 这里只是演示,生产环境请使用 lua-resty-jwt 库
local decoded = ngx.decode_base64(token)
if not decoded then
ngx.status = 401
ngx.say('{"error": "Invalid token"}')
return ngx.exit(401)
end
-- 验证通过,将用户信息传给后端
ngx.req.set_header("X-User-Id", "extracted-user-id")
🌟 实战:动态路由(灰度发布)
-- lua/gray_route.lua
-- 灰度发布路由
local gray_users = ngx.shared.gray_users -- 灰度用户列表
local function is_gray_user(user_id)
if gray_users:get(user_id) then
return true
end
-- 也可以按百分比灰度
local hash = ngx.crc32_long(user_id)
local percent = hash % 100
return percent < 10 -- 10% 的用户走灰度
end
-- 获取用户 ID(从 header 或 cookie)
local user_id = ngx.req.get_headers()["X-User-Id"] or "anonymous"
if is_gray_user(user_id) then
-- 灰度用户 → 新版本服务
ngx.var.backend = "http://service-v2:8080"
else
-- 正常用户 → 稳定版本服务
ngx.var.backend = "http://service-v1:8080"
end
📊 OpenResty vs SpringCloud Gateway
| 特性 | OpenResty | SpringCloud Gateway |
|---|---|---|
| 语言 | Lua | Java |
| 性能 | 极高(C + LuaJIT) | 高(Reactor) |
| 内存占用 | 极低 | 较高 |
| 学习成本 | 需要学 Lua + Nginx | Java 生态内 |
| 生态 | Lua 库 | Spring 生态 |
| 适用场景 | 超高并发、边缘计算 | 微服务网关 |
| 动态配置 | 修改 Lua 文件 + reload | 配置中心 |
如何选择?
- 超高并发(10万+ QPS)→ OpenResty
- Spring 生态内,团队都是 Java 技术栈 → SpringCloud Gateway
- 两者结合:OpenResty 做边缘网关,SpringCloud Gateway 做内部网关
📝 小结
- OpenResty = Nginx + LuaJIT,高性能 Web 平台
- 常用场景:API 网关、限流、鉴权、灰度发布
- Lua 代码在 Nginx 不同阶段执行(access、content 等)
- 性能极高,适合超高并发场景
- 可以和 SpringBoot 后端服务配合使用
➡️ 下一步
最后一章!来看看 最佳实践与常见坑,这是从实战中总结出来的经验。
💪 练习题
- 安装 OpenResty,创建一个返回 JSON 的简单 API。
- 实现一个基于 IP 的简单限流中间件。
- OpenResty 和 SpringCloud Gateway 各有什么优缺点?
- 在 OpenResty 中,
access_by_lua和content_by_lua分别在什么阶段执行?
答案提示
- 参考本章的 Hello World 示例
- 使用
ngx.shared共享内存 + IP 作为 key 计数 - OpenResty 性能更高但需学 Lua,Gateway 在 Spring 生态内开发方便
access_by_lua在访问控制阶段(鉴权/限流),content_by_lua在内容生成阶段(响应)
