Skip to content

Instantly share code, notes, and snippets.

@kindy
Created June 24, 2012 14:55
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save kindy/2983544 to your computer and use it in GitHub Desktop.
Save kindy/2983544 to your computer and use it in GitHub Desktop.
在 ngx_lua 中实现类似 php 的被嵌入 html 功能
"abc"
<?= 124 ?>
<?= a ?>
<? local x = 12
if math.random(1, 5) > 1 then ?>
xxx
<? else ?>
yyy
<? end ?>
-- 在 http://www.savarese.com/software/ltp/ 获取 ltp
-- lposix 可以在 https://github.com/rrthomas/luaposix.git 获取
-- 把 ltp 目录和当前文件放到 ngx_lua 可搜索的地方 在希望使用模板的nginx配置中添加以下定义即可
local ltp = require 'ltp.template'
local posix = nil
do
local ok, ret = pcall(require, 'posix')
if ok then
posix = ret
end
end
local ltp_cache = {}
module(..., package.seeall)
-- in: filename
-- in: mode - 1 force cache, 2 nocache, 3 mtime cache
-- out: render function
function loadltp(path, mode)
mode = mode or 1
if mode == 3 and not posix then
mode = 2
end
if ltp_cache[path] then
if mode == 1 then
return ltp_cache[path][2]
elseif mode == 2 then
ltp_cache[path] = nil
elseif mode == 3 then
if assert(posix.stat(path)).mtime < ltp_cache[1] then
return ltp_cache[path][2]
else
ltp_cache[path] = nil
end
end
end
local con = assert(io.open(ngx.var.request_filename, 'rb')):read('*a')
local str = assert(ltp.compile_template_as_function(con, '<?', '?>'))
local fn = assert(loadstring(str))()
ltp_cache[path] = {ngx.time(), fn}
return fn
end
function render(path)
path = path or ngx.var.request_filename
local fn = assert(loadltp(path))
local ctx = {}
setmetatable(ctx, {__index = _G})
local ret = {}
setfenv(fn, ctx)
fn(ret)
ngx.print(ret)
end
#在 http://www.savarese.com/software/ltp/ 下载 http://www.savarese.com/downloads/ltp/ltp-1.0.4.tar.bz2
#把 ltp 目录放到 ngx_lua 可搜索的地方 在希望使用模板的nginx配置中添加以下定义即可
#模板中可使用任意 lua 模块,如果想设置通用的对象,可在 ctx 变量中指定
#模板例子见 a.ltp
location ~ \.ltp$ {
content_by_lua "
local ctx = {
a = 2;
}
local ltp = require 'ltp.template'
local con = assert(io.open(ngx.var.request_filename, 'rb')):read('*a')
local str = assert(ltp.compile_template_as_function(con, '<?', '?>'))
local fn = assert(loadstring(str))()
local ret = {}
setmetatable(ctx, {__index = _G})
setfenv(fn, ctx)
fn(ret)
ngx.print(ret)
";
}
# 注意不要让其他 nginx 的 location 定义覆盖了这里的,那样你的源码就暴露了!!!!!!
# nginx 很容易出这样的问题
location ~ \.ltp$ {
default_type text/html;
content_by_lua " require 'ltp_util'.render() ";
}
@agentzh
Copy link

agentzh commented Jun 24, 2012

直接 ngx.print(ret) 效率更高,因为可以免去拼接字符串的巨大开销。ngx.print 和 ngx.say 都支持字符串数组作为参数。

@agentzh
Copy link

agentzh commented Jun 24, 2012

同时,通过用户 Lua 模块级的变量来缓存 ltp 编译模版的结果,避免每请求都现编一次,可以极大地提高效率 :) 同时也可以避免每请求去现读磁盘 ;)

@kindy
Copy link
Author

kindy commented Jun 24, 2012

嗯嗯, ngx.print(ret) 可以有。
不过在用户态缓存可能不能简单全量缓存,毕竟传统用户习惯了改改文件就刷新之类。

@agentzh
Copy link

agentzh commented Jun 24, 2012 via email

@foglede
Copy link

foglede commented Jun 24, 2012

我强烈建议你吧。把 改成 可以么。
好处有三
第一 这个是HTML的标准注释 注释不解析是方便的,而且即便是很多不支持LUA的ide也不至于出错。
第二 跟PHP 5.4 + 以后的版本严重冲突啊。你有没有想过 如果你是个PHP程序员转过来的,写<? 以后 后面跟着是lua代码很奇怪?
第三 明示 阅读代码的小鸟 可能还在猜 这东西看着像 ruby啊 不对 更像NODEJS。 如果有了 小鸟一看 天哪这居然是我没看过的lua啊。

@kindy
Copy link
Author

kindy commented Jun 25, 2012

呃,个人比较喜欢 php 的这个标记风格。当然啦,你可以自己修改成任意想要的风格,
修改 local str = assert(ltp.compile_template_as_function(con, ''))
里面的 标记即可。。
比如 local str = assert(ltp.compile_template_as_function(con, ''))
这也是自己写的好处哈。。

@foglede
Copy link

foglede commented Sep 23, 2012

local ltp = require("ltp.template")
ltp.render(io.stdout, 1, request.app_path .. "/lua.html", false, {}, '', { total="2400" })

然后怎么直接输出?不用NGX呢?

@kindy
Copy link
Author

kindy commented Sep 24, 2012

@fokite 你是要在哪里使用呢?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment