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