Nginx中高级动态重定向应由rewrite处理静态路径转换、Lua处理动态逻辑:rewrite仅支持正则替换,无法实现基于用户身份或请求头的条件跳转;access_by_lua_block可在鉴权阶段用ngx.redirect()直接重定向,set_by_lua_block适合预计算URL后配合return使用。

在 Nginx 中结合 rewrite 和 Lua 脚本实现高级动态重定向,核心在于:用 rewrite 做轻量、静态路径转换,用 access_by_lua_block(或 set_by_lua_block)做动态决策,两者分工协作——rewrite 不适合复杂逻辑,Lua 才是动态重定向的主力。
明确 rewrite 和 Lua 的职责边界
rewrite 指令本身只支持正则匹配 + 字符串替换,无法访问数据库、请求头以外的变量、或执行条件分支。一旦需要根据用户身份、设备类型、A/B 测试分组、实时黑名单等做跳转,就必须交由 Lua 处理。
-
rewrite ^/old/(.*)$ /new/$1 permanent;—— 适合固定路径迁移 -
rewrite ^/api/v1/(.*)$ /api/v2/$1 break;—— 内部重写,不暴露给客户端 - 但
rewrite无法判断$http_user_agent是否含 “Mobile” 后再跳转,这类逻辑必须进 Lua
用 access_by_lua_block 实现动态重定向
在 location 块中使用 access_by_lua_block,可在鉴权阶段完成重定向决策,避免后续处理开销。Nginx 变量(如 $arg_token、$http_referer)可直接在 Lua 中读取,也可调用 ngx.redirect() 发起 301/302 跳转。
- 示例:按来源域名白名单跳转
location /redirect {
access_by_lua_block {
local referer = ngx.var.http_referer or ""
local allowed_domains = {["example.com"] = true, ["trusted-site.org"] = true}
local domain = string.match(referer, "https?://([^/]+)")
if not (domain and allowed_domains[domain]) then
ngx.redirect("https://example.com/unauthorized", 302)
return
end
}
proxy_pass http://backend;
}- 注意:
ngx.redirect()会终止当前请求,后续配置(如proxy_pass)不再执行 - 若需保留原始 URI 参数,用
ngx.redirect(redirect_url, 302)即可自动携带
用 set_by_lua_block 预计算重定向目标
当重定向地址需拼接变量、查表或简单计算时,可用 set_by_lua_block 提前生成目标 URL,并赋值给自定义变量,再在 rewrite 或 return 中引用。这种方式更轻量,适合无阻塞逻辑。
- 示例:根据请求参数
lang动态生成跳转路径
set_by_lua_block $redirect_url {
local lang = ngx.var.arg_lang or "en"
local paths = { en = "/home", zh = "/首页", ja = "/ホーム" }
return "https://example.com" .. (paths[lang] or paths.en)
}
location /i18n {
return 302 $redirect_url;
}-
set_by_lua_block必须放在server或location顶层,不能嵌套在其他指令内 - 返回值会被自动转为字符串,直接用于
return或rewrite
绕过 rewrite 的常见误区与替代方案
不要在 rewrite 中试图调用 Lua 函数——它不支持。也不建议把所有逻辑塞进 access_by_lua_block 做 ngx.exec() 内部重写,因为 ngx.exec() 不改变 URL,对 SEO 和浏览器地址栏无效。真正需要“重定向”效果(即浏览器地址变更),一律用 ngx.redirect() 或 return 30X。
- 错误写法:
rewrite .* /lua_handler last;+ 在/lua_handlerlocation 中ngx.redirect()—— 多一次内部跳转,增加延迟 - 推荐写法:在原始 location 直接
ngx.redirect(),一步到位 - 若需兼容旧 rewrite 规则,可在 Lua 中解析
ngx.var.uri后手动构造跳转地址,无需依赖 rewrite 指令


















