zoukankan      html  css  js  c++  java
  • ngx_lua 随笔

    --[[
    test
    --]]
    ngx.header.content_type = "text/plain"; --输出头部
    local user = ngx.var.arg_user -- 定义user变量并获取url中的参数 http://localhost?user=hello
    local sys = ngx.var.server_name -- 获取nginx中的变量
    ngx.say (user); -- 输出至页面
    ngx.say (sys);

    if user== "spam" then
    local res=ngx.location.capture("/lua") -- capture
    if res.status == 200 then
    ngx.print("capture:",res.body)
    end
    end

    tbl = {"alpha", "beta", "gamma"} --定义table 数组
    table.insert(tbl, "delta") --增加数组元素
    table.sort( tbl, sortLevelNameAsc ) -- 数组排序

    for i = 1, table.getn(tbl) do -- for循环
    ngx.say(string.format("%s", tbl[i])) -- string format
    end

    local deled=table.remove(tbl, 2) -- 删除指定位置元素并返回删除元素.如果没有指定删除的位置,则默认删除table的最后一个元素
    ngx.say ("delete the second element " .. deled ) -- 字符串连接 ..


    gTable = {}
    gTable.name = "eric"
    gTable.gender = "man"
    gTable.phonenumber = "0000000000"
    gTable[1] = "公司"
    gTable[2] = "部门"
    gTable.hobby = {"跑步", "读书", "游戏", "动漫"} -- 多维table,可以通过gTable.hobby[1]的方式访问.即gTable.hobby本身也是一个table
    gTable.secTable = {}
    gTable.secTable.job = "程序员"
    gTable.secTable.label = "写代码的"
    gTable.secTable.description = "职责是实现产品的逻辑"

    for index, value in pairs(gTable) do
    ngx.say(string.format("%s:%s", index, value)) -- string format
    if ("table" == type(value)) then
    for idx, var in pairs(value) do
    ngx.say(string.format("二维table:%s:%s", idx, var)) -- string format
    end
    end
    end

    --[[
    输出结果如下:
    1 公司
    2 部门
    hobby table: 0x7fdceac14bc0
    二维table: 1 跑步
    二维table: 2 读书
    二维table: 3 游戏
    二维table: 4 动漫
    phonenumber 0000000000
    gender man
    secTable table: 0x7fdceac15100
    二维table: label 写代码的
    二维table: description 职责是实现产品的逻辑
    二维table: job 程序员
    name eric
    --]]

    ngx.say (table.concat( tbl, ":")) -- join
    ngx.say(#tbl) -- 返回数组个数
    ngx.say(os.time()) -- 1423643892
    ngx.say(os.date()) -- Wed Feb 11 16:38:12 2015
    ngx.say(os.date("%m/%d/%Y",os.time())) -- 02/11/2015
    ngx.say(os.date("%Y-%m-%d %H:%M:%S",1423643892)) -- 2015-02-11 16:38:12 time to date
    ngx.say(os.time{year="2015", month="2", day="11", hour="16",min="38",sec="12"}) -- 1423643892 date to time


    ngx.say(tonumber("100")+11) --字符与数字的显式转换 输出结果为:111
    ngx.say(type(tostring(100))) --转换成字符串 并获取类型 输出结果为:string
    ngx.say(string.len("hello")) --字符串长度 输出结果为:5
    ngx.say(string.sub("hello Lua", 7,9)) --截取字符串 输出结果为:Lua

    ngx.say(math.random(1,2)); --随机数

    ngx.print(ngx.req.raw_header(),ngx.var.uri) -- 获取http header 信息
    --[[
    获取ip
    --]]
    local function getip( )
    local myIP = ngx.req.get_headers()["X-Real-IP"]
    if myIP == nil then
    myIP = ngx.req.get_headers()["x_forwarded_for"]
    end
    if myIP == nil then
    myIP = ngx.var.remote_addr
    end
    return myIP
    end
    ngx.print(getip()) --调取函数 按顺序,必须先申明方法 才能调用

    ngx.redirect("http://www.elong.com") --跳转 

     多行字符串

    local longstring=[[123
    456
    abc
    'szSuffix'
    ]]
    ngx.say(longstring)

    ngx_lua安装

    ngx_lua安装可以通过下载模块源码,编译Nginx,但是推荐采用openresty。Openresty就是一个打包程序,包含大量的第三方Nginx模块,比如HttpLuaModule,HttpRedis2Module,HttpEchoModule等。省去下载模块,并且安装非常方便。

            ngx_openresty bundle: openresty

            ./configure --with-luajit&& make && make install

            默认Openresty中ngx_lua模块采用的是标准的Lua5.1解释器,通过--with-luajit使用LuaJIT。

    ngx.location.capture

    location = /other {  
        ehco 'Hello, world!';  
    }  
          
    # Lua非阻塞IO  
    location = /lua {  
        content_by_lua '  
            local res = ngx.location.capture("/other?id=12")  
            if res.status == 200 then  
                ngx.print(res.body)  
            end  
        ';  
    }  

     capture post

    -- POST https://www.example.com:443/foo/bar?hello=world

    ngx.req.set_header("Content-Type", "application/json;charset=utf8"); ngx.req.set_header("Accept", "application/json"); local res = ngx.location.capture('/proxy/https/www.example.com/443/foo/bar', { method = ngx.HTTP_POST, body = body, args = {hello = 'world'} });

    ngx.location.capture_multi

    语法:res1,res2, ... = ngx.location.capture_multi({ {uri, options?}, {uri, options?}, ...})

            与ngx.location.capture功能一样,可以并行的、非阻塞的发出多个子请求。这个方法在所有子请求处理完成后返回,并且整个方法的运行时间取决于运行时间最长的子请求,并不是所有子请求的运行时间之和。

    # 同时发送多个子请求(subrequest)  
    location = /moon {  
        ehco 'moon';  
    }  
    location = /earth {  
        ehco 'earth';  
    }  
           
    location = /lua {  
        content_by_lua '  
            local res1,res2 = ngx.location.capture_multi({ {"/moon"}, {"earth"} })  
            if res1.status == 200 then  
                ngx.print(res1.body)  
            end  
            ngx.print(",")  
            if res2.status == 200 then  
                ngx.print(res2.body)  
            end  
        ';  
    }  

    set_by_lua

    和set指令一样用于设置Nginx变量并且在rewrite阶段执行,只不过这个变量是由lua脚本计算并返回的。

            语法:set_by_lua$res <lua-script-str> [$arg1 $arg2 ...]

    location = /adder {  
        set_by_lua $res "  
                local a = tonumber(ngx.arg[1])  
                    local b = tonumber(ngx.arg[2])  
                    return a + b" $arg_a $arg_b;  
       
            echo $res;  
    }  

    set_by_lua_file

    执行Nginx外部的lua脚本,可以避免在配置文件中使用大量的转义

    location = /fib {  
            set_by_lua_file $res "conf/adder.lua" $arg_n;  
       
            echo $res;  
    }  

     adder.lua:

    local a = tonumber(ngx.arg[1])  

    local b = tonumber(ngx.arg[2])  

    return a + b  

     

    access_by_lua和access_by_lua_file

            运行在access阶段,用于访问控制。Nginx原生的allow和deny是基于ip的,通过access_by_lua能完成复杂的访问控制,比如,访问数据库进行用户名、密码验证等。

    location /auth {  
        access_by_lua '  
            if ngx.var.arg_user == "ntes" then  
                return  
            else   
                Ngx.exit(ngx.HTTP_FORBIDDEN)  
            end  
        ';  
        echo 'welcome ntes';  
    }  

     输出:

    $ curl 'localhost/auth?user=sohu'  
    $ Welcome ntes  
      
      
    $ curl 'localhost/auth?user=ntes'  
    $ <html>  
    <head><title>403 Forbidden</title></heda>  
    <body bgcolor="white">  
    <center><h1>403 Forbidden</h1></center>  
    <hr><center>ngx_openresty/1.0.10.48</center>  
    </body>  
    </html>  

    rewrite_by_lua和rewrite_by_lua_file

            实现url重写,在rewrite阶段执行。

            配置:

    location = /foo {  
            rewrite_by_lua 'ngx.exec("/bar")';  
        echo 'in foo';  
    }  
      
    location = /bar {  
            echo 'Hello, Lua!';  
    }  

    输出:

    $ curl 'localhost/lua'  
    $ Hello, Lua!

    content_by_lua和content_by_lua_file

     Contenthandler在content阶段执行,生成http响应。由于content阶段只能有一个handler,所以在与echo模块使用时,不能同时生效,我测试的结果是content_by_lua会覆盖echo。这和之前的hello world的例子是类似的。

    location = /lua {  
            content_by_lua 'ngx.say("Hello, Lua!")';  
    }  

    os.execute ([command])
    功能:相当于C的system函数,返回系统状态码

    例如:
    os.execute("pause")

    输出:
    按任意键继续. . .

    os.exit ([code])
    功能:相当于C的exit函数,终止主程序,code为返回值

    例如:
    os.exit(1)

    os.getenv (varname)

    例如:

    print(os.getenv("USERDOMAIN"))
    print(os.getenv("SystemRoot"))
    print(os.getenv("Os2LibPath"))
    print(os.getenv("ProgramFiles" ))
    print(os.getenv("APPDATA" ))
    print(os.getenv("ALLUSERSPROFILE" ))
    print(os.getenv("CommonProgramFiles" ))
    print(os.getenv("COMPUTERNAME" ))
    print(os.getenv("USERNAME"))
    print(os.getenv("USERPROFILE" ))
    print(os.getenv("ComSpec"))
    print(os.getenv("LOGONSERVER" ))
    print(os.getenv("NUMBER_OF_PROCESSORS" ))
    print(os.getenv("OS"))
    print(os.getenv("PATHEXT" ))
    print(os.getenv("PROCESSOR_ARCHITECTURE" ))
    print(os.getenv("PROCESSOR_IDENTIFIER" ))
    print(os.getenv("PROCESSOR_LEVEL" ))
    print(os.getenv("PROCESSOR_REVISION" ))
    print(os.getenv("USERDOMAIN"))
    print(os.getenv("SystemRoot" ))
    print(os.getenv("TEMP"))

    输出:

    RDEV
    C:WINDOWS
    nil
    C:Program Files
    C:Documents and SettingsaiyunApplication Data
    C:Documents and SettingsAll Users
    C:Program FilesCommon Files
    BAIYUN
    baiyun
    C:Documents and Settingsaiyun
    C:WINDOWSsystem32cmd.exe
    http://www.cnblogs.com/whiteyun/admin/file://rdev1/
    2
    Windows_NT
    .COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.py;.pyw;.wlua
    x86
    x86 Family 15 Model 6 Stepping 5, GenuineIntel
    15
    0605
    RDEV
    C:WINDOWS
    C:DOCUME~1aiyunLOCALS~1Temp

    os.remove (filename)
    功能:删除文件或一个空目录,若函数调用失败则返加nil加错误信息

    os.rename (oldname, newname)
    功能:更改一个文件或目录名,若函数调用失败则返加nil加错误信息

    调取 mysql json redis操作

    ngx.say("=============== mysql ==============")
    local mysql = require "resty.mysql"
    local db,err = mysql:new()
    if not db then
    ngx.say("failed to instantiate mysql: ",err)
    return
    end
    db:set_timeout(1000)
    local ok,err,errno,sqlstate = db:connect{
    host = "127.0.0.1",
    port = 3306,
    database = "el_agency",
    user = "root",
    password = "",
    max_package_size = 1024
    }
    if not ok then
    ngx.say("failed to connect: ", err, ": ", errno, " ", sqlstate)
    return
    end
    db:query("set names utf8")
    ngx.say("connected to mysql.") res,err,errno,sqlstate = db:query("select username,appKey,secretKey from tbl_user limit 2") if not res then ngx.say("bad result: ", err, ": ", errno, ": ", sqlstate, ".") return end
    db:close()
    ngx.say("=============== cjson ==============") local cjson = require "cjson"; local res1=cjson.encode(res); ngx.say(res1); local res2=cjson.decode(res1); print_lua_table(res2); ngx.say("=============== redis ==============") local redis = require("resty.redis") local client = redis:new() client:set_timeout(1000) -- 1 second local ok,err = client:connect("127.0.0.1",6379) if not ok then ngx.say("failed to connect: ",err) return end client:set("hello","world"); local res,err = client:get("hello") if not res then ngx.say("failed to get",err) return end
    client:close()
    ngx.say(res)

    执行顺序

    1.init_by_lua  上下文http  ngx启动时执行
    2.set_by_lua  上下文 server, server if, location, location if
    3.rewrite_by_lua 上下文  http, server, location, location if
    4.access_by_lua 上下文 http, server, location, location if
    5.content_by_lua 上下文   location, location if
    6.header_filter_by_lua 上下文   http, server, location, location if
    7.body_filter_by_lua 上下文 http, server, location, location if
    8.log_by_lua 上下文 http, server, location, location if

     lua中 三目运算符的实现

    (a and b) or c <==> a ? b : c

     lua urlencode urldecode URL编码

    function decodeURI(s)
        s = string.gsub(s, '%%(%x%x)', function(h) return string.char(tonumber(h, 16)) end)
        return s
    end
    
    function encodeURI(s)
        s = string.gsub(s, "([^%w%.%- ])", function(c) return string.format("%%%02X", string.byte(c)) end)
        return string.gsub(s, " ", "+")
    end

    或者
    ngx.escape_uri() 字符串的url编码
    ngx.unescape_uri() 字符串url解码
     

      LUA require 搜索路径指定方法

    如果是一个 *.LUA 的文件, 里面用到了自己写的库, 或者第三方写的库, 但是你不想把它放到 lua 的安装目录里, 则在代码里面可以指定require搜索的路径。
    
    
        package.path = '/usr/local/share/lua/5.1/?.lua;/home/resty/?.lua;;'    --搜索lua模块 ;;指定默认路径
        package.cpath = '/usr/local/lib/lua/5.1/?.so;;'        --搜索so模块
    
    
    如果是要在 nginx.conf 文件中引用第三方的库,则需要在 http 段中添加下面的代码
    
        lua_package_path '/usr/local/share/lua/5.1/?.lua;/home/resty/?.lua;';
        lua_package_cpath '/usr/local/lib/lua/5.1/?.so;';

    lua下面dump出一个table的结构

    --- @brief 调试时打印变量的值  
    --- @param data 要打印的字符串  
    --- @param [max_level] table要展开打印的计数,默认nil表示全部展开  
    --- @param [prefix] 用于在递归时传递缩进,该参数不供用户使用于  
    --- @ref http://dearymz.blog.163.com/blog/static/205657420089251655186/  
    function var_dump(data, max_level, prefix)  
        if type(prefix) ~= "string" then  
            prefix = ""  
        end  
        if type(data) ~= "table" then  
            print(prefix .. tostring(data))  
        else  
            print(data)  
            if max_level ~= 0 then  
                local prefix_next = prefix .. "    "  
                print(prefix .. "{")  
                for k,v in pairs(data) do  
                    io.stdout:write(prefix_next .. k .. " = ")  
                    if type(v) ~= "table" or (type(max_level) == "number" and max_level <= 1) then  
                        print(v)  
                    else  
                        if max_level == nil then  
                            var_dump(v, nil, prefix_next)  
                        else  
                            var_dump(v, max_level - 1, prefix_next)  
                        end  
                    end  
                end  
                print(prefix .. "}")  
            end  
        end  
    end  

    ngx.exec

     location @cc {
                internal;
                root   html;
                index  index.html index.htm;
    }
    
    代码中
    ngx.exec("@cc")

    iptolong

    -- 参数:待分割的字符串,分割字符  
    -- 返回:子串表.(含有空串)  
    function split(s, delim)
        if type(delim) ~= "string" or string.len(delim) <= 0 then
            return
        end
    
        local start = 1
        local t = {}
        while true do
        local pos = string.find (s, delim, start, true) -- plain find
            if not pos then
              break
            end
    
            table.insert (t, string.sub (s, start, pos - 1))
            start = pos + string.len (delim)
        end
        table.insert (t, string.sub (s, start))
    
        return t
    end
    
    --ip转整数
    function ip2long(ip)
      local ips=split(ip,".")
      local num = 0
      for i,v in pairs(ips) do
        num =num +(tonumber(v) * math.pow(256,#ips-i)) 
      end
      return num
    end

    获取当前路径及上级目录

    function dirname(str)  
        if str:match(".-/.-") then  
            local name = string.gsub(str, "(.*/)(.+)", "%1")  
            return name  
        elseif str:match(".-\.-") then  
            local name = string.gsub(str, "(.*\)(.+)", "%1")  
            return name  
        else  
            return ''  
        end  
    end  
    
    local __FILE__ = debug.getinfo(1,'S').source:sub(2)
    ROOT_PATH=dirname(__FILE__)

    lua 创建一个“类” 并返回“类”中的所有方法

    --helper.lua
    
    local _M = { _VERSION = '0.09' }
    
    function _M.to_hex(s)
    
    end
    
    function _M.atoi (s)
    
    end
    
    return _M
    
    
    
    local helper=require 'helper'
    
    var_dump(helper)
    
    返回
    
    ["to_hex"] = function: 0x0cd26038,
    ["atoi"] = function: 0x0cd260e8,
    ["_VERSION"] = "0.09",

    package.seeall

    --game.lua
    module(..., package.seeall) --- ...不定参数
    function play()
        return "ok just do it"end
    function quit()
        return "welcome back again"end
    
    --require local game=require 'game' ngx.say(game:play())

     Nginx中Lua模块的运行机制

    Nginx中的每个Worker进程使用一个lua虚拟机,工作进程中的所有协程共享虚拟机。将Nginx中的lua API封装好之后注入到lua的VM中就可以在lua代码中进行访问

    异常捕获pcall

    local user = ngx.var.arg_user
    local st,err=pcall(function()
    if user == "spam" then local res=ngx.location.capture("/lua") -- capture if res.status == 200 then ngx.print("capture:",res.body) end else error("出错啦") end
    end); if not st then ngx.say(err) end

    ----类似于php

    try{
      if (user == "spam"){
          //todo
      }else{
        throw New Exception("出错啦")
      }

    }catch(Exception $ex){
    echo $ex->getMessage();
    }

     

  • 相关阅读:
    麦茶商务的网站
    jQuery Ajax 实例 ($.ajax、$.post、$.get)
    关于meta知多少
    WebApp之Meta标签
    html5开发之viewport使用
    bootstrap
    8.8&8.9 dp训练小结
    2019.8.10小结
    2019.8.17 小结
    [NOI2001]炮兵阵地 题解
  • 原文地址:https://www.cnblogs.com/wangxusummer/p/4286305.html
Copyright © 2011-2022 走看看