zoukankan      html  css  js  c++  java
  • 高并发 Nginx+Lua OpenResty系列(8)——Lua模版渲染

    高并发 Nginx+Lua OpenResty系列(8)——Lua模版渲染

    模版渲染

    location /luatemplatetest {
    			#first match ngx location(首先匹配位置) html下的templates
    			set $template_location "/templates";  
    			#then match root read file(其次匹配位置)
    			set $template_root "C:/openresty/openresty-1.15.8.3-win64/templates";
    
    			access_log  logs/luatemplatetest.access.log  main;
                default_type text/html;
    			# 即缓存lua代码,即每次lua代码变更必须reload nginx才生效,
    			# 如果在开发阶段可以通过lua_code_cache off;关闭缓存,
    			# 这样调试时每次修改lua代码不需要reload nginx;但是正式环境一定记得开启缓存
    			lua_code_cache on;
                # content_by_lua_block  {
                #     ngx.say("<p>hello, world ...... </p>")
                # }
                content_by_lua_file conf/lua/test2.lua;
    			# 与html同级的目录
    			# root templates;
    			
    			
            }
    

      

    动态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还提供了不需要解析片段、简单布局、可复用的代码块、宏指令等支持。

    下载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中即可。
    接下来就可以通过如下代码片段引用了:

    local template = require("resty.template")
    

    模版位置

    我们需要告诉lua-resty-template去哪儿加载我们的模块,此处可以通过set指令定义template_location、template_root或者从root指令定义的位置加载。
    我们可以在openResty.conf配置文件的server部分定义

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

    也可以通过在server部分定义root指令

    root /usr/openResty/templates;
    

    其顺序是

    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
    

    内容为

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


  • 相关阅读:
    121.买卖股票 求最大收益1 Best Time to Buy and Sell Stock
    409.求最长回文串的长度 LongestPalindrome
    202.快乐数 Happy Number
    459.(KMP)求字符串是否由模式重复构成 Repeated Substring Pattern
    326.是否为3的平方根 IsPowerOfThree
    231.是否为2的平方根 IsPowerOfTwo
    461.求两个数字转成二进制后的“汉明距离” Hamming Distance
    206.反转单链表 Reverse Linked List
    448. 数组中缺少的元素 Find All Numbers Disappeared in an Array
    常见表单元素处理
  • 原文地址:https://www.cnblogs.com/xiao-xue-di/p/12972909.html
Copyright © 2011-2022 走看看