Nginx重写阶段实现复杂URL重定向应使用rewrite_by_lua*指令,在rewrite阶段动态干预URI、修改变量或跳转,需启用ngx_http_lua_module,不可在if块内使用,支持基于请求特征的条件跳转及子请求决策。

在 Nginx 重写阶段用 Lua 实现复杂 URL 重定向,核心是使用 rewrite_by_lua* 指令(如 rewrite_by_lua_block 或 rewrite_by_lua_file),它在 rewrite 阶段执行,早于 location 匹配完成,能动态干预 URI、修改变量、触发跳转,且支持完整 Lua 逻辑与 Nginx 变量交互。
rewrite_by_lua* 是重写阶段的正确入口
不同于 access_by_lua*(鉴权阶段)或 content_by_lua*(响应生成阶段),rewrite_by_lua* 在 Nginx 的 rewrite 阶段运行,此时请求 URI 尚未最终确定,但已解析出 $uri、$args、$host 等关键变量,适合做路径改写、参数增强、条件跳转等前置决策。
- 必须启用
ngx_http_lua_module(推荐直接使用 OpenResty) - 不能在
if块内使用;应放在location或server块顶层 - 脚本中调用
ngx.redirect()或ngx.exec()会立即生效,后续 rewrite 规则不再执行
根据请求特征做动态重定向
利用 Lua 可读取任意 Nginx 变量(如用户代理、IP、Header、参数),实现比原生 if 更灵活的判断逻辑:
- 按设备类型跳转:
if ngx.var.http_user_agent:match("Android|iPhone") then ngx.redirect("https://m.example.com" .. ngx.var.uri, 302) end - 按查询参数分流:
local args = ngx.req.get_uri_args() if args.ab == "v2" then return ngx.exec("/ab/v2" .. ngx.var.uri) end - 按来源域名跳转:
if ngx.var.host ~= "www.example.com" then ngx.redirect("https://www.example.com" .. ngx.var.request_uri, 301) end
结合子请求做服务端决策跳转
真正“复杂”的跳转往往依赖后端逻辑(如权限校验、A/B 版本判定、灰度路由)。Lua 可通过 ngx.location.capture 发起内部子请求,拿到结果后再决定重定向目标:
- 先调用鉴权接口:
local res = ngx.location.capture("/auth?token=" .. ngx.var.arg_token) - 根据响应状态跳转:
if res.status == 403 then ngx.redirect("/login?r=" .. ngx.var.uri, 302) end - 支持并发子请求(
ngx.location.capture_multi)提升多条件判断效率
注意执行顺序与变量作用域
rewrite 阶段 Lua 脚本中的行为会影响后续流程,需明确几个关键点:
-
ngx.redirect()发送 HTTP 3xx 响应给客户端,地址栏变化;必须加return避免继续执行(如return ngx.redirect(...)) -
ngx.exec()是内部重定向,不发响应,URI 重置后重新匹配 location;等价于rewrite ... last - 不能在 rewrite_by_lua 中修改
$uri或$args后再靠原生 rewrite 指令捕获——Lua 改写后,原生 rewrite 不会自动重匹配;应由 Lua 全权处理跳转逻辑 - 避免循环:例如 redirect 到自身路径又触发同段 Lua,需加 guard 条件(如检查
$arg_redirected是否已存在)


















