動(dòng)態(tài) web 網(wǎng)頁開發(fā)是 Web 開發(fā)中一個(gè)常見的場景,比如像京東商品詳情頁,其頁面邏輯是非常復(fù)雜的,需要使用模板技術(shù)來實(shí)現(xiàn)。而 Lua 中也有許多模板引擎,如目前我在使用的 lua-resty-template,可以渲染很復(fù)雜的頁面,借助 LuaJIT 其性能也是可以接受的。
如果學(xué)習(xí)過 JavaEE 中的 servlet 和 JSP 的話,應(yīng)該知道 JSP 模板最終會(huì)被翻譯成Servlet 來執(zhí)行;而 lua-resty-template 模板引擎可以認(rèn)為是 JSP,其最終會(huì)被翻譯成 Lua 代碼,然后通過 ngx.print 輸出。
而 lua-resty-template 和大多數(shù)模板引擎是類似的,大體內(nèi)容有:
首先需要下載 lua-resty-template
Java 代碼
cd /usr/example/lualib/resty/
wget https://raw.githubusercontent.com/bungle/lua-resty-template/master/lib/resty/template.lua
mkdir /usr/example/lualib/resty/html
cd /usr/example/lualib/resty/html
wget https://raw.githubusercontent.com/bungle/lua-resty-template/master/lib/resty/template/html.lua
接下來就可以通過如下代碼片段引用了
Java 代碼
local template = require("resty.template")
我們需要告訴 lua-resty-template 去哪兒加載我們的模塊,此處可以通過 set 指令定義template_location、template_root 或者從 root 指令定義的位置加載。
如我們可以在 example.conf 配置文件的 server 部分定義
Java 代碼
\#first match ngx location
set $template_location "/templates";
\#then match root read file
set $template_root "/usr/example/templates";
也可以通過在server部分定義root指令
Java 代碼
root /usr/example/templates;
其順序是
Java 代碼
local function load_ngx(path)
local file, location = path, ngx_var.template_location
if file:sub(1) == "/" then file = file:sub(2) end
if location and location ~= "" then
if location:sub(-1) == "/" then location = location:sub(1, -2) end
local res = ngx_capture(location .. '/' .. file)
if res.status == 200 then return res.body end
end
local root = ngx_var.template_root or ngx_var.document_root
if root:sub(-1) == "/" then root = root:sub(1, -2) end
return read_file(root .. "/" .. file) or path
end
此處建議首先 template_root,如果實(shí)在有問題再使用 template_location,盡量不要通過 root 指令定義的 document_root 加載,因?yàn)槠浔旧淼暮x不是給本模板引擎使用的。
接下來定義模板位置
Java 代碼
mkdir /usr/example/templates
mkdir /usr/example/templates2
example.conf 配置 server 部分
Java 代碼
\#first match ngx location
set $template_location "/templates";
\#then match root read file
set $template_root "/usr/example/templates";
location /templates {
internal;
alias /usr/example/templates2;
}
首先查找 /usr/example/template2,找不到會(huì)查找 /usr/example/templates。
然后創(chuàng)建兩個(gè)模板文件
Java 代碼
vim /usr/example/templates2/t1.html
內(nèi)容為
Java 代碼
template2
Java 代碼
vim /usr/example/templates/t1.html
內(nèi)容為
Java 代碼
template1
test_temlate_1.lua
Java 代碼
local template = require("resty.template")
template.render("t1.html")
example.conf 配置文件
Java 代碼
location /lua_template_1 {
default_type 'text/html';
lua_code_cache on;
content_by_lua_file /usr/example/lua/test_template_1.lua;
}
訪問如 http://192.168.1.2/lua_template_1
將看到 template2 輸出。然后 rm/usr/example/templates2/t1.html,reload nginx 將看到 template1 輸出。
接下來的測試我們會(huì)把模板文件都放到 /usr/example/templates 下。
使用模板引擎目的就是輸出響應(yīng)內(nèi)容;主要用法兩種:直接通過 ngx.print 輸出或者得到模板渲染之后的內(nèi)容按照想要的規(guī)則輸出。
Java 代碼
local template = require("resty.template")
--是否緩存解析后的模板,默認(rèn)true
template.caching(true)
--渲染模板需要的上下文(數(shù)據(jù))
local context = {title = "title"}
--渲染模板
template.render("t1.html", context)
ngx.say("<br/>")
--編譯得到一個(gè)lua函數(shù)
local func = template.compile("t1.html")
--執(zhí)行函數(shù),得到渲染之后的內(nèi)容
local content = func(context)
--通過ngx API輸出
ngx.say(content)
常見用法即如下兩種方式:要么直接將模板內(nèi)容直接作為響應(yīng)輸出,要么得到渲染后的內(nèi)容然后按照想要的規(guī)則輸出。
Java 代碼
location /lua_template_2 {
default_type 'text/html';
lua_code_cache on;
content_by_lua_file /usr/example/lua/test_template_2.lua;
}
Java 代碼
local template = require("resty.template")
local context = {
title = "測試",
name = "張三",
description = "<script>alert(1);</script>",
age = 20,
hobby = {"電影", "音樂", "閱讀"},
score = {語文 = 90, 數(shù)學(xué) = 80, 英語 = 70},
score2 = {
{name = "語文", score = 90},
{name = "數(shù)學(xué)", score = 80},
{name = "英語", score = 70},
}
}
template.render("t3.html", context)
請確認(rèn)文件編碼為 UTF-8;context 即我們渲染模板使用的數(shù)據(jù)。
Java 代碼
{(header.html)}
<body>
{# 不轉(zhuǎn)義變量輸出 #}
姓名:{* string.upper(name) *}<br/>
{# 轉(zhuǎn)義變量輸出 #}
簡介:{{description}}<br/>
{# 可以做一些運(yùn)算 #}
年齡: {* age + 1 *}<br/>
{# 循環(huán)輸出 #}
愛好:
{% for i, v in ipairs(hobby) do %}
{% if i > 1 then %},{% end %}
{* v *}
{% end %}<br/>
成績:
{% local i = 1; %}
{% for k, v in pairs(score) do %}
{% if i > 1 then %},{% end %}
{* k *} = {* v *}
{% i = i + 1 %}
{% end %}<br/>
成績2:
{% for i = 1, #score2 do local t = score2[i] %}
{% if i > 1 then %},{% end %}
{* t.name *} = {* t.score *}
{% end %}<br/>
{# 中間內(nèi)容不解析 #}
{-raw-}{(file)}{-raw-}
{(footer.html)}
模板最終被轉(zhuǎn)換為 Lua 代碼進(jìn)行執(zhí)行,所以模板中可以執(zhí)行任意 Lua 代碼。
Java 代碼
location /lua_template_3 {
default_type 'text/html';
lua_code_cache on;
content_by_lua_file /usr/example/lua/test_template_3.lua;
}
訪問如 http://192.168.1.2/lua_template_3
進(jìn)行測試。
基本的模板引擎使用到此就介紹完了。