一、概述

lua是一种轻量小巧的脚本语言,用规范C语言编写并以源代码方式敞开,其设计意图是为了嵌入应用程序中,从而为应用程序供给灵敏的扩展和定制功用。

官网:www.lua.org/

lua 语法介绍与 NGINX lua 高档用法实战操作

二、lua 装置

curl -L -R -O https://www.lua.org/ftp/lua-5.4.6.tar.gz
tar zxf lua-5.4.6.tar.gz
cd lua-5.4.6
make all test

测试

vim hello.lua
# 添加打印
print("Hello World!")
# 运行
lua hello.lua

指令形式

lua

三、lua 语法

1)lua 数据类型

Lua 是一种轻量级的脚本语言,具有简练、灵敏的数据类型。以下是 Lua 中的一些根本数据类型:

类型 描述 示例
nil 表示没有值或许一个无效的值。在 Lua 中,变量默许初始化为 nil。 local myVar = nil
布尔类型(boolean) 有两个值,true 和 false。 local isTrue = true
local isFalse = false
数字类型(number) 表示整数或浮点数。 local integerNumber = 42
local floatNumber = 3.14
字符串类型(string) 由字符组成的序列。
字符串能够运用单引号或双引号界说。
也能够运用两边括号界说长字符串。
local myString = “Hello, Lua!”
local singleQuoted = ‘Single quoted string’
local doubleQuoted = “Double quoted string”
local longString = [[
This is a long string
that spans multiple lines.
]]
表(table) 相似于字典或关联数组,是 Lua 中唯一的杂乱数据结构 local myTable = {key1 = “value1”, key2 = “value2”}
#表中的元素能够经过键来拜访。
print(myTable.key1) — 输出: value1
函数(function) 表示一个可履行的代码块。 local function add(a, b)
return a b
end

local result = add(3, 4)
print(result) — 输出: 7

这些根本数据类型的组合和运用,以及 Lua 供给的灵敏的表达式和操控结构,使得 Lua 成为编写脚本、装备文件、嵌入式体系等场景的抱负语言。在运用 Lua 进行编程时,熟悉这些数据类型的特性和用法是很重要的。

2)lua 变量

Lua 中,变量是用来存储数据值的标识符。Lua 是一种动态类型的脚本语言,因而不需求显式声明变量的类型。以下是一些关于 Lua 变量的根本规矩和示例:

  1. 变量命名规矩: 变量名是由字母、数字和下划线组成的字符串,不能以数字开头。Lua 是大小写敏感的,因而 myVariableMyVariable 被视为不同的变量。

  2. 变量声明和赋值: 变量能够直接赋值,不需求事前声明。假如测验拜访一个没有赋值的变量,其值将为 nil

myVariable = 42
anotherVariable = "Hello, Lua!"
  1. 多重赋值Lua 支撑多重赋值,能够在一行中给多个变量赋值。
a, b, c = 1, 2, 3

此刻,a 的值为 1,b 的值为 2,c 的值为 3。

  1. 全局变量和局部变量: 默许状况下,所有变量都是全局的。假如需求创立一个局部变量,能够运用关键字 local
local localVar = "I am local"

局部变量的效果规模限定在声明它的代码块内,而全局变量在整个程序中可见。

  1. nil 值: 在 Lua 中,未初始化的变量的值为 nil,表示没有值或无效值。
local uninitializedVar
print(uninitializedVar)  -- 输出: nil
  1. 删去变量Lua 没有供给直接删去变量的语法,但能够将变量赋值为 nil,以开释其内存。
myVariable = nil

这些是 Lua 中运用变量的根本规矩。在实际编程中,注意效果域、防止全局变量乱用、运用有意义的变量名等是良好的编程习惯。

3)lua 拼接字符串

Lua 中,能够运用不同的办法来拼接字符串。以下是一些常见的字符串拼接办法:

  1. 运用 .. 运算符: Lua 中的字符串拼接能够运用 .. 运算符。这个运算符将两个字符串衔接在一起。
local str1 = "Hello, "
local str2 = "Lua!"
local result = str1 .. str2
print(result)  -- 输出: Hello, Lua!
  1. 运用 string.format 函数string.format 函数能够用于格式化字符串,也能够用来拼接字符串。
local name = "John"
local age = 25
local result = string.format("My name is %s and I am %d years old.", name, age)
print(result)  -- 输出: My name is John and I am 25 years old.
  1. 运用 .. 运算符衔接多个字符串: 能够运用 .. 运算符衔接多个字符串,构成更杂乱的拼接。
local part1 = "Hello, "
local part2 = "how are "
local part3 = "you?"
local result = part1 .. part2 .. part3
print(result)  -- 输出: Hello, how are you?
  1. 运用表衔接字符串: 将字符串存储在表中,然后运用 table.concat 函数进行衔接。
local strings = {"Hello, ", "Lua!"}
local result = table.concat(strings)
print(result)  -- 输出: Hello, Lua!
  1. 运用迭代衔接字符串: 能够运用迭代器将多个字符串衔接起来。
local strings = {"Hello, ", "how ", "are ", "you?"}
local result = ""
for _, str in ipairs(strings) do
    result = result .. str
end
print(result)  -- 输出: Hello, how are you?

这些办法中,挑选适合你需求的方式来拼接字符串。一般来说,.. 运算符是最简单和直观的办法,而 table.concat 在处理大量字符串时或许更高效。

4)lua 循环

Lua 供给了多种循环结构,能够依据不同的需求挑选合适的循环类型。以下是 Lua 中常用的循环结构:

  1. while 循环: 当给定的条件为真时,while 循环会一直履行。
local i = 1
while i <= 5 do
    print(i)
    i = i   1
end
  1. repeat … until 循环: 与 while 循环相似,但条件在循环结束时进行检查。即便条件一开始就为真,循环至少会履行一次。
local i = 1
repeat
    print(i)
    i = i   1
until i > 5
  1. for 数值型循环遍历数值规模内的值。
for i = 1, 5 do
    print(i)
end

这个例子会输出 1 到 5 的数字。

  1. for 泛型循环: 遍历表中的元素。
local fruits = {"apple", "banana", "orange"}
for index, value in ipairs(fruits) do
    print(index, value)
end

这个例子会输出表中的索引和对应的值。

  • for 迭代器循环: 运用自界说迭代器遍历元素。
function squares(n)
    return function()
        n = n   1
        return n, n * n
    end
end
for i, square in squares(3) do
    print(i, square)
end

这个例子会输出从 4 开始的平方数。

  1. 循环操控句子Lua 供给了 breakgoto 句子,用于在循环中进行操控流程。
for i = 1, 10 do
    if i == 5 then
        break  -- 跳出循环
    end
    print(i)
end
local i = 1
::mylabel::  -- 界说标签
if i <= 5 then
    print(i)
    i = i   1
    goto mylabel  -- 跳转到标签
end

请注意,goto 在许多编程环境中被认为是不良实践,由于它或许导致代码不易理解和维护。尽量运用其他循环结构和操控句子来完成代码逻辑。

5)lua 函数

Lua 中,函数是一等公民,能够用来组织和结构化代码。以下是 Lua 中界说和运用函数的根本办法:

  1. 界说函数: 运用 function 关键字来界说函数,后跟函数名和参数列表。函数体包含在 end 关键字之前。
function greet(name)
    print("Hello, " .. name .. "!")
end
  1. 调用函数: 运用函数名和恰当的参数列表来调用函数。
greet("John")

这会输出 “Hello, John!”。

  1. 返回值: 函数能够返回一个或多个值。运用 return 句子返回值。
function add(a, b)
    return a   b
end
local result = add(3, 4)
print(result)  -- 输出: 7
  1. 多返回值Lua 支撑多返回值。函数能够返回多个值,用逗号分隔。
function multipleValues()
    return 1, 2, 3
end
local a, b, c = multipleValues()
print(a, b, c)  -- 输出: 1 2 3
  1. 匿名函数: 能够运用匿名函数(也称为 lambda 函数)。
local square = function(x)
    return x * x
end
print(square(5))  -- 输出: 25

或许运用箭头函数(Lua 5.2 及以上版别):

local square = (x) => x * x
print(square(5))  -- 输出: 25
  1. 函数作为参数: 能够将函数作为参数传递给其他函数。
function apply(func, value)
    return func(value)
end
local result = apply(square, 5)
print(result)  -- 输出: 25
  1. 可变参数: 运用 ... 表示可变参数。能够在函数内部经过 arg 表来拜访这些参数。
function sum(...)
    local total = 0
    for _, value in ipairs{...} do
        total = total   value
    end
    return total
end
print(sum(1, 2, 3, 4, 5))  -- 输出: 15
  1. 闭包(Closure)Lua 支撑闭包,即在函数内部界说的函数能够拜访外部函数的局部变量。
function outer()
    local x = 10
    function inner()
        return x
    end
    return inner
end
local closure = outer()
print(closure())  -- 输出: 10
  1. 尾调用优化: Lua 支撑尾调用优化,即在函数的最后一个动作是调用另一个函数时,不会增加堆栈深度。这有助于防止堆栈溢出。
function factorial_tail_recursive(n, acc)
    acc = acc or 1
    if n <= 1 then
        return acc
    else
        return factorial_tail_recursive(n - 1, n * acc)
    end
end
print(factorial_tail_recursive(5))  -- 输出: 120

这些是 Lua 中函数的根本用法。函数在 Lua 中是非常灵敏和强壮的东西,它们支撑多种编程形式,包含面向对象编程和函数式编程。

6)lua 条件操控

Lua 中的条件操控主要经过ifelseifelse 句子来完成。以下是 Lua 中条件操控的根本语法和示例:

  1. if 句子: 用于履行一个条件表达式,假如条件为真,则履行相应的代码块。
local x = 10
if x > 0 then
    print("x is positive")
end
  1. if-else 句子: 用于履行两个代码块中的一个,取决于条件表达式的成果。
local x = -5
if x > 0 then
    print("x is positive")
else
    print("x is non-positive")
end
  1. if-elseif-else 句子: 用于履行多个条件表达式,挑选第一个为真的代码块。
local x = 0
if x > 0 then
    print("x is positive")
elseif x < 0 then
    print("x is negative")
else
    print("x is zero")
end
  1. 嵌套的 if 句子: 能够在一个 if 句子的代码块中嵌套另一个 if 句子。
local x = 10
local y = 5
if x > 0 then
    print("x is positive")
    if y > 0 then
        print("y is also positive")
    end
end
  1. 条件表达式: 条件表达式的成果能够是任何能转换为布尔值的表达式。一般,任何非 nilfalse 的值都被认为是真。
local x = 42
if x then
    print("x is truthy")
else
    print("x is falsy")
end
  1. 短路运算Lua 支撑短路运算,即在逻辑表达式中运用 andor 运算符时,假如确定成果的话就不再持续计算。
local x = 5
local y = 10
local result = (x > 0) and (y / x) or 0
print(result)  -- 输出: 2

这些是 Lua 中条件操控的根本用法。条件操控句子答应依据不同的条件履行不同的代码块,使得程序能够依据不同状况做出不同的决策。

7)lua 库模块

Lua 供给了一些核心的库模块,这些模块包含了一些常用的功用,以及用于处理字符串、文件、网络等使命的东西。以下是 Lua 中一些常见的库模块:

  1. string 模块: 供给了字符串处理的函数,包含拼接、查找、替换等操作。
local str1 = "Hello"
local str2 = "Lua"
local result = string.format("%s, %s!", str1, str2)
print(result)  -- 输出: Hello, Lua!
  1. table 模块: 供给了对 Lua 表(table)进行操作的函数,包含排序、衔接、查找等操作。
local fruits = {"banana", "apple", "orange"}
table.sort(fruits)
print(table.concat(fruits, ", "))  -- 输出: apple, banana, orange
  1. math 模块: 供给了数学函数,如三角函数、指数函数、对数函数等。
local x = 5
local y = math.sqrt(x)
print(y)  -- 输出: 2.2360679774998
  1. io 模块: 供给了输入和输出的函数,用于读写文件、操控台等。
local file = io.open("example.txt", "w")
file:write("Hello, Lua!")
file:close()
local file = io.open("example.txt", "r")
local content = file:read("*a")
file:close()
print(content)  -- 输出: Hello, Lua!
  1. os 模块: 供给了一些与操作体系相关的函数,如履行体系指令、获取当前时刻等。
local currentTime = os.time()
print(currentTime)
  1. debug 模块: 供给了一些用于调试的函数,如获取栈信息、设置断点等。
function foo()
    print(debug.traceback("Stack trace:"))
end
foo()
  1. coroutine 模块: 供给了协程(coroutine)的支撑,答应非抢占式的多使命编程。
local co = coroutine.create(function()
    print("Coroutine 1")
    coroutine.yield()
    print("Coroutine 2")
end)
coroutine.resume(co)  -- 输出: Coroutine 1
coroutine.resume(co)  -- 输出: Coroutine 2
  1. package 模块: 供给了 Lua 的模块管理功用,用于加载其他 Lua 文件或库。
local myModule = require("mymodule")
myModule.myFunction()
  1. cjson 模块: cjson有两个模块:cjson和cjson.safe,前者在解析失利后会抛出反常,而后者则返回nil。

文档地址:github.com/openresty/l…

# 解析失利不会抛反常
local cjson = require "cjson.safe"
# 解析失利会抛反常
local cjson = require "cjson"

序列化

local obj = {
        code = 0,
        msg = "恳求成功"
}
local json = cjson.encode(obj)

反序列化

local json = '{{"id":10001,"name":"SALSA AIR"}'
-- 反序列化
local obj = cjson.decode(json)
cjson.decode([[{"code":0,"msg":"恳求成功"}]])
  1. redis 模块:openResty供给了操作Redis的模块,咱们只需求引进该模块就能直接运用:
-- 引进redis模块
local redis = require('resty.redis')
-- 初始化Redis对象
local red = redis:new()
-- 设置redis超时时刻
red:set_timeout(1000, 1000, 1000)

封装衔接池函数:用来开释Redis衔接,其实是开释衔接池

-- 关闭redis衔接的东西办法,其实是放入衔接池
local function close_redis(red)
    local pool_max_idle_time = 10000 -- 衔接的闲暇时刻,单位是毫秒
    local pool_size = 100 --衔接池大小
    local ok, err = red:set_keepalive(pool_max_idle_time, pool_size)
    if not ok then
        ngx.log(ngx.ERR, "放入redis衔接池失利: ", err)
    end
end

封装获取数据的函数

-- 查询redis的办法 ip和port是redis地址,key是查询的key
local function read_redis(ip, port, key)
    -- 获取一个衔接
    local ok, err = red:connect(ip, port)
    if not ok then
        ngx.log(ngx.ERR, "衔接redis失利 : ", err)
        return nil
    end
    -- 查询redis
    local resp, err = red:get(key)
    -- 查询失利处理
    if not resp then
        ngx.log(ngx.ERR, "查询Redis失利: ", err, ", key = " , key)
    end
    --得到的数据为空处理
    if resp == ngx.null then
        resp = nil
        ngx.log(ngx.ERR, "查询Redis数据为空, key = ", key)
    end
    close_redis(red)
    return resp
end

封装需求暗码和db索引的函数

local function read_redis(ip, port, password, db_index, key)
    -- 获取一个衔接
    local ok, err = red:connect(ip, port)
    if not ok then
        ngx.log(ngx.ERR, "衔接redis失利 : ", err)
        return nil
    end
    -- 暗码和挑选的库
    red:auth(password)
    red:select(db_index)
    -- 查询redis
    local resp, err = red:get(key)
    -- 查询失利处理
    if not resp then
        ngx.log(ngx.ERR, "查询Redis失利: ", err, ", key = " , key)
    end
    --得到的数据为空处理
    if resp == ngx.null then
        resp = nil
        ngx.log(ngx.ERR, "查询Redis数据为空, key = ", key)
    end
    close_redis(red)
    return resp
end

四、NGINX lua 高档用法

NGINX with Lua 是指在 NGINX 服务器上运用 Lua 编程语言进行定制化开发和扩展功用。Lua 是一种轻量级、高效的脚本语言,能够嵌入到各种应用程序和服务中。经过将 Lua 引擎集成到 NGINX 中,能够完成更灵敏的装备、恳求处理、身份验证等功用。

lua 语法介绍与 NGINX lua 高档用法实战操作

nginx 布置与介绍能够参阅我以下几篇文章:

以下是一些 NGINX with Lua 的常见应用场景:

  1. 恳求处理和重写: 运用 Lua 能够编写自界说的恳求处理逻辑,例如 URL 重写、参数处理、恳求头修正等。经过在 NGINX 装备中嵌入 Lua 脚本,能够完成更高档的恳求处理。
location /example {
    content_by_lua_block {
        ngx.say("Hello from NGINX with Lua!")
    }
}
  1. 拜访操控和身份验证: Lua 能够用于完成自界说的拜访操控逻辑,例如根据用户、IP 地址、恳求内容等的身份验证和授权。这使得能够依据详细需求定制灵敏的拜访战略。
location /admin {
    access_by_lua_block {
        local user = ngx.var.remote_user
        if user ~= "admin" then
            ngx.exit(ngx.HTTP_FORBIDDEN)
        end
    }
}
  1. 呼应处理和过滤: Lua 能够用于在 NGINX 接收到后端服务的呼应后进跋涉一步的处理,例如过滤呼应内容、修正呼应头号。
location /backend {
    proxy_pass http://backend_server;
    body_filter_by_lua_block {
        ngx.arg[1] = string.gsub(ngx.arg[1], "foo", "bar")
    }
}
  1. 动态内容生成: 运用 Lua 能够动态生成内容,例如根据后端服务的呼应数据或其他外部数据源。
location /dynamic {
    content_by_lua_block {
        local args = ngx.req.get_uri_args()
        if args["enable_feature"] == "true" then
            ngx.say("Feature is enabled!")
        else
            ngx.say("Feature is disabled.")
        end
    }
}
  1. 调用外部服务: Lua 能够经过 ngx.location.capture 等方式调用外部服务,完成与其他服务的集成。
location /api {
    content_by_lua_block {
        local res = ngx.location.capture("/external-api")
        ngx.say("Response from External API: ", res.body)
    }
}
  1. 高档恳求处理: Lua 能够用于更灵敏的恳求处理,例如在恳求处理流程中进行动态的重定向、缓存操控等。
location /dynamic_redirect {
    content_by_lua_block {
        local args = ngx.req.get_uri_args()
        if args["redirect"] == "true" then
            ngx.redirect("/new_location", ngx.HTTP_MOVED_TEMPORARILY)
        else
            ngx.say("No redirection.")
        end
    }
}
  1. 自界说日志: Lua 能够用于自界说 NGINX 的日志记载,以便记载特定信息或格式化日志输出。
http {
    log_by_lua_block {
        ngx.log(ngx.NOTICE, "Custom log message")
    }
    # 其他装备...
}
  1. 反向署理和负载均衡: 运用 Lua 能够对恳求进行更杂乱的负载均衡战略,例如根据恳求参数、cookie 等条件进行动态的反向署理挑选。
http {
    upstream backend {
        server backend1;
        server backend2;
    }
    server {
        location / {
            proxy_pass http://backend;
            proxy_next_upstream error timeout http_500 http_502 http_503 http_504;
        }
    }
}
  1. WebSocket 支撑: Lua 能够用于处理 WebSocket 衔接,完成更高档的 WebSocket 功用。
location /websocket {
    proxy_pass http://backend;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    content_by_lua_block {
        -- Lua WebSocket处理逻辑
    }
}
  1. 运用 Lua 第三方库: Lua 能够运用第三方库来扩展功用,例如运用 LuaRocks 装置和运用第三方模块。
http {
    lua_package_path "/path/to/lua/?.lua;;";
    init_by_lua_block {
        require("my_custom_module")
    }
    # 其他装备...
}

这些是 NGINX Lua 模块的一些高档用法。经过结合 Lua 的强壮脚本能力和 NGINX 的高性能特性,能够完成各种杂乱的定制化需求。注意在运用 Lua 模块时要保证版别兼容性和安全性。

【温馨提示】默许状况下 Nginx 不支撑 Lua 模块,需求装置 LuaJIT 解说器,并且重新编译Nginx,或许可运用国人开发的Openrestry

lua 语法介绍与 NGINX lua 高档用法实战操作解说就先到这里了,有任何疑问也可关注我大众号:大数据与云原生技能分享,进行技能交流,如本篇文章对您有所帮助,麻烦帮助一键三连(点赞、转发、收藏)~

lua 语法介绍与 NGINX lua 高档用法实战操作