高併發 Nginx+Lua OpenResty系列(8)——Lua模版渲染

模版渲染

動態web網頁開發是Web開發中一個常見的場景,好比像京東商品詳情頁,其頁面邏輯是很是複雜的,須要使用模板技術來實現。而Lua中也有許多模板引擎,如目前京東在使用的lua-resty-template,能夠渲染很複雜的頁面,藉助LuaJIT其性能也是能夠接受的。


若是學習過JavaEE中的servlet和JSP的話,應該知道JSP模板最終會被翻譯成Servlet來執行;而lua-resty-template模板引擎能夠認爲是JSP,其最終會被翻譯成Lua代碼,而後經過ngx.print輸出。


而lua-resty-template和大多數模板引擎是相似的,大致內容有:
模板位置:從哪裏查找模板;
變量輸出/轉義:變量值輸出;
代碼片斷:執行代碼片斷,完成如if/else、for等複雜邏輯,調用對象函數/方法;
註釋:解釋代碼片斷含義;
include:包含另外一個模板片斷;
其餘:lua-resty-template還提供了不須要解析片斷、簡單佈局、可複用的代碼塊、宏指令等支持。html

下載lua-resty-template

wget https://github.com/bungle/lua-resty-template/archive/v1.9.tar.gz
tar -xvzf v1.9.tar.gz

解壓後能夠看到lib/resty下面有一個template.lua,這個就是咱們所須要的,在template目錄中還有兩個lua文件,將這兩個文件複製到/usr/openResty/lualib/resty中便可。
接下來就能夠經過以下代碼片斷引用了:nginx

local template = require("resty.template")

模版位置

咱們須要告訴lua-resty-template去哪兒加載咱們的模塊,此處能夠經過set指令定義template_location、template_root或者從root指令定義的位置加載。
咱們能夠在openResty.conf配置文件的server部分定義git

# first match ngx location
set $template_location "/templates";
# then match root read file
set $template_root "/usr/openResty/templates";

也能夠經過在server部分定義root指令github

root /usr/openResty/templates;

其順序是web

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
  1. 經過ngx.location.capture從template_location查找,若是找到(狀態爲爲200)則使用該內容做爲模板;此種方式是一種動態獲取模板方式;
  2. 若是定義了template_root,則從該位置經過讀取文件的方式加載模板;
  3. 若是沒有定義template_root,則默認從root指令定義的document_root處加載模板。


    此處建議首先template_root,若是實在有問題再使用template_location,儘可能不要經過root指令定義的document_root加載,由於其自己的含義不是給本模板引擎使用的。


    接下來定義模板位置
mkdir /usr/openResty/templates
mkdir /usr/openResty/templates2

openResty.conf配置文件

# first match ngx location
set $template_location "/templates";
# then match root read file
set $template_root "/usr/openResty/templates";

location /templates {
    internal;
    alias /usr/openResty/templates2;
}

首先查找/usr/openResty/template2,找不到會查找/usr/openResty/templates。
而後建立兩個模板文件緩存

vi /usr/openResty/templates2/t1.html

內容爲svg

template2
vi /usr/example/templates/t1.html

內容爲函數

template1

test_temlate_1.lua

local template = require("resty.template")
template.render("t1.html")

openResty.conf配置文件

location /lua_template_1 {
    default_type 'text/html';
    lua_code_cache on;
    content_by_lua_file /usr/openResty/lua/test_template_1.lua;
}

訪問如http://127.0.0.1/lua_template_1將看到template2輸出。而後rm /usr/openResty/templates2/t1.html,reload nginx將看到template1輸出。
接下來的測試咱們會把模板文件都放到/usr/openResty/templates下。佈局

API

使用模板引擎目的就是輸出響應內容;主要用法兩種:直接經過ngx.print輸出或者獲得模板渲染以後的內容按照想要的規則輸出。性能

test_template_2.lua

local template = require("resty.template")
--是否緩存解析後的模板,默認true
template.caching(true)
--渲染模板須要的上下文(數據)
local context = {title = "title"}
--渲染模板
template.render("t1.html", context)

ngx.say("<br/>")
--編譯獲得一個lua函數
local func = template.compile("t1.html")
--執行函數,獲得渲染以後的內容
local content = func(context)
--經過ngx API輸出
ngx.say(content)

常見用法即以下兩種方式:要麼直接將模板內容直接做爲響應輸出,要麼獲得渲染後的內容而後按照想要的規則輸出。

openResty.conf配置文件

location /lua_template_2 {  
    default_type 'text/html';  
    lua_code_cache on;  
    content_by_lua_file /usr/openResty/lua/test_template_2.lua;  
}

使用示例

test_template_3.lua

local template = require("resty.template")

local context = {
  title = "測試",
  name = "張三",
  description = "<script>alert(1);</script>",
  age = 20,
  hobby = {"電影", "音樂", "閱讀"},
  score = {語文 = 90, 數學 = 80, 英語 = 70},
  score2 = {
    {name = "語文", score = 90},
    {name = "數學", score = 80},
    {name = "英語", score = 70},
  }
}

template.render("t3.html", context)

模板文件/usr/openResty/templates/t3.html

<html>
  <head>
    <meta charset="UTF-8" />
  </head>
  <body>
    {# 不轉義變量輸出 #}
    姓名:{* string.upper(name) *}<br/>
    {# 轉義變量輸出 #}
    簡介:{{description}}<br/>
    {# 能夠作一些運算 #}
    年齡: {* age + 1 *}<br/>
    {# 循環輸出 #}
    愛好:
    {% 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/>
    {# 中間內容不解析 #}
    {-raw-}{(file)}{-raw-}
  </body>
</html>

{(include_file)}:包含另外一個模板文件;
{* var *}:變量輸出;
{{ var }}:變量轉義輸出;
{% code %}:代碼片斷;
{# comment #}:註釋;
{-raw-}:中間的內容不會解析,做爲純文本輸出;
模板最終被轉換爲Lua代碼進行執行,因此模板中能夠執行任意Lua代碼。

openResty.conf配置文件

location /lua_template_3 {
    default_type 'text/html';
    lua_code_cache on;
    content_by_lua_file /usr/openResty/lua/test_template_3.lua;
}

訪問如http://127.0.0.1/lua_template_3進行測試。 基本的模板引擎使用到此就介紹完了。

相關文章
相關標籤/搜索