高并发 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进行测试。 基本的模板引擎使用到此就介绍完了。

相关文章
相关标签/搜索