跳转到主内容
极星编程网:以代码为星,赴技术山海!

如何在Apache中利用mod_lua编写自定义的轻量级请求改写逻辑实战

mod_lua仅支持轻量无状态预处理,如修改请求头、重写URI路径、简单参数清洗及返回状态码;不支持读取POST body、调用外部API、数据库查询、multipart解析或HMAC签名验证。 不能用 mod_lua 实现复杂请求改写,比如重写整个请求体、动态拼接 JSON 参数或做业务级路由决策。它只适合在 Apache 请求生命周期的早期阶段,做轻量、无状态、不依赖外部 I/O 的预处理动作——例如修改请求头、重写 URI 路径片段、拦截特定模式请求并提前返回。 适用场景:哪些改写能做、哪些坚决不能做 mod_lua 的定位是“钩子(hook)”,不是“应用服务器”。它的执行环境受限于 Apache 子进程生命周期,没有独立事件循环,也不支持阻塞式网络调用或文件读写。 能做的 :根据 Host、User-Agent、URI 前缀等已有字段,改写
r.uri
或
r.filename
;添加/覆盖
r.headers_in
中的字段(如注入 X-Forwarded-For);对 GET 参数做简单清洗;基于规则返回 403/404/302。 不能做的 :读取原始 POST body(除非显式开启
lua_request_body on
,且仍受限于 Apache 缓存策略);调用外部 API 校验 token;连接数据库查路由表;解析 multipart 表单;做 HMAC 签名验证(需完整 body + 密钥 + crypto,mod_lua 不提供安全可靠的 hmac 实现)。 核心配置与脚本结构 改写逻辑必须挂载在 Apache 的请求处理链中,推荐使用
LuaHookHandler
(在 handler 阶段介入)或
LuaHookTranslate
(在 URI 映射前介入),后者更适合路径改写。 在虚拟主机或目录块中启用:
LuaHookTranslate /path/to/rewrite.lua handle_rewrite
确保模块已加载:
LoadModule lua_module modules/mod_lua.so
禁用生产环境缓存(仅开发):
LuaCodeCache off
脚本示例(
rewrite.lua
): Apache 2.4.62 PHP中文网提供Apache 2.4.62 官方 tar.gz 源码包下载,通过源码编译安装,开发者能够灵活定制模块、优化性能并精准控制安装路径,满足多样化的业务需求。 下载
function handle_rewrite(r) local uri = r.uri -- 把 /api/v2/xxx 改成 /v2/xxx if string.match(uri, "^/api/v2/") then r.uri = string.gsub(uri, "^/api", "") return apache2.OK end -- 拦截含 test=1 的请求,重定向到 /debug local args = r:parseargs() if args.test == "1" then r.headers_out["Location"] = "/debug" r.status = 302 return apache2.DONE end end
常见陷阱与绕过方案 直接操作
r.uri
后,Apache 默认不会重新匹配 RewriteRule 或 Location 块——这意味着改写后的路径可能无法命中你预期的后端配置。 若需触发重匹配,加标志
[E=REWRITE_DONE:1]
并配合
RewriteCond %{ENV:REWRITE_DONE} ^1$
做二次判断(但会增加开销)。 更稳妥的做法:把所有路径改写逻辑统一收口到 Lua,避免混用 mod_rewrite 和 mod_lua。 URI 中的中文或特殊字符要先 decode:
uri = string.gsub(uri, "%%([0-9A-Fa-f][0-9A-Fa-f])", function(h) return string.char(tonumber(h, 16)) end)
调试与生效确认 mod_lua 错误默认静默,不报错也不记录,极易误判为“脚本没运行”。 强制输出日志:在脚本开头加
r:info("rewrite triggered for " .. r.uri)
,再查
ErrorLog
。 确认是否加载:用
apachectl -M | grep lua
查模块状态;用
curl -I http://host/test.lua
测试 .lua 文件能否被解释(仅限开发环境)。 改脚本后必须重载 Apache(
systemctl reload httpd
),
touch
文件无效。

相关文章