OpenResty
OpenResty® 是一個基於 Nginx 與 Lua 的高效能 Web 平台,其內部整合了大量精良的 Lua 庫、第三方模組以及大多數的依賴項。用於方便地搭建能夠處理超高並行、擴充套件性極高的動態 Web 套用、Web 服務和動態閘道器。
OpenResty® 透過匯聚各種設計精良的 Nginx 模組(主要由 OpenResty 團隊自主開發),從而將 Nginx 有效地變成一個強大的通用 Web 套用平台。這樣,Web 開發人員和系統工程師可以使用 Lua 手稿語言調動 Nginx 支持的各種 C 以及 Lua 模組,快速構造出足以勝任 10K 乃至 1000K 以上單機並行連線的高效能 Web 套用系統。
Lua簡介
Lua 以其簡潔優雅的設計和卓越的效能,在全球程式語言家族中獨樹一幟。它是一門輕量級、可嵌入式的手稿語言,設計之初便以高效、靈活和易於擴充套件為目標。Lua名字來源於葡萄牙語中的「月亮」,寓意其小巧卻蘊含強大能量。
Lua語法清晰簡潔,學習曲線平緩,適合快速開發和原型驗證,尤其在遊戲開發、網路編程、配置檔解析等領域擁有廣泛的套用。同時,Lua的跨平台特性使得它能夠在Windows、Linux、Mac OS等多種作業系統上自由執行。
Lua 編碼規範
縮排
在 OpenResty 中使用 4 個空格作為縮排的標記,雖然 Lua 並沒有這樣的語法要求。
--No
if a then
ngx.say("hello Tinywan")
end
--yes
if a then
ngx.say("hello Tinywan")
end
你可以在使用的編輯器中,把 tab 改為 4 個空格,來簡化操作。
空格
在操作符的兩邊,都需要用一個空格來做分隔:
--No
local i=1
local s = "Tinywan"
--Yes
local i = 1
local s = "Tinywan"
空行
不少開發者會把其他語言的開發習慣帶到 OpenResty 中來,比如在行尾增加一個分號。
--No
if a then
ngx.say("hello Tinywan");
end;
增加分號會讓 Lua 程式碼顯得非常醜陋,也是沒有必要的。另外,不要為了節省程式碼的行數,後者為了顯得「簡潔」,而把多行程式碼變為一行。這樣會在定位錯誤的時候不知道到底那一段程式碼出了問題:
--No
if a then ngx.say("hello Tinywan") end
--yes
if a then
ngx.say("hello Tinywan")
end
函式之間需要用兩個空行來做分隔:
--No
localfunction foo()
end
localfunction bar()
end
--Yes
localfunction foo()
end
localfunction bar()
end
如果有多個
if elseif
的分支,它們之間需要一個空行來做分隔:
--No
if a == 1 then
foo()
elseif a== 2 then
bar()
elseif a == 3 then
run()
else
error()
end
--Yes
if a == 1 then
foo()
elseif a== 2 then
bar()
elseif a == 3 then
run()
else
error()
end
每行最大長度
每行不能超過 80 個字元,超過的話,需要換行並對齊:
--No
return limit_conn_new("plugin-limit-conn", conf.conn, conf.burst, conf.default_conn_delay)
--Yes
return limit_conn_new("plugin-limit-conn", conf.conn, conf.burst,
conf.default_conn_delay)
在換行對齊的時候,要體現出上下兩行的對應關系。就上面的範例而言,第二行函式的參數,要在第一行左括弧的右邊。
如果是字串拼接的對齊,需要把
..
放到下一行中:
--No
return limit_conn_new("plugin-limit-conn" .. "plugin-limit-conn" ..
"plugin-limit-conn")
--Yes
return limit_conn_new("plugin-limit-conn" .. "plugin-limit-conn"
.. "plugin-limit-conn")
變量
應該永遠使用局部變量,不要使用全域變量:
--No
i = 1
s = "Tinywan"
--Yes
local i = 1
local s = "Tinywan"
變量命名使用
snake_case
風格:
--No
local IndexArr = 1
local str_Name = "Tinywan"
--Yes
local index_arr = 1
local str_name = "Tinywan"
對於常量要使用全部大寫:
--No
local max_int = 65535
local server_name = "Tinywan"
--Yes
local MAX_INT = 65535
local SERVER_NAME = "Tinywan"
陣列
使用
table.new
來預先分配陣列:
--No
local t = {}
for i = 1, 100 do
t[i] = i
end
--Yes
local new_tab = require "table.new"
local t = new_tab(100, 0)
for i = 1, 100 do
t[i] = i
end
不要在陣列中使用
nil
:
--No
local t = {1, 2, nil, 3}
如果一定要使用空值,請用
ngx.null
來表示:
--No
local t = {1, 2, ngx.null, 3}
字串
不要在熱程式碼路徑上拼接字串:
--No
local s = ""
for i = 1, 100000 do
s = s .. "a"
end
--Yes
local t = {}
for i = 1, 100000 do
t[i] = "a"
end
local s = table.concat(t, "")
函式
函式的命名也同樣遵循
snake_case
:
--No
localfunction testNginx()
end
--Yes
localfunction test_nginx()
end
函式應該盡可能早的返回:
--No
localfunction check(age, name)
local ret = true
if age < 20 then
ret = false
end
if name == "a"then
ret = false
end
-- do something else
return ret
end
--Yes
localfunction check(age, name)
if age < 20 then
returnfalse
end
if name == "a"then
returnfalse
end
-- do something else
returntrue
end
模組
所有
require
的庫都要
local
化:
--No
localfunction foo()
local ok, err = ngx.timer.at(delay, handler)
end
--Yes
local timer_at = ngx.timer.at
localfunction foo()
local ok, err = timer_at(delay, handler)
end
為了風格的統一,
require
和
ngx
也需要
local
化:
--No
local core = require("apisix.core")
local timer_at = ngx.timer.at
localfunction foo()
local ok, err = timer_at(delay, handler)
end
--Yes
local ngx = ngx
local require = require
local core = require("apisix.core")
local timer_at = ngx.timer.at
localfunction foo()
local ok, err = timer_at(delay, handler)
end
錯誤處理
對於有錯誤資訊返回的函式,必須對錯誤資訊進行判斷和處理:
--No
local sock = ngx.socket.tcp()
local ok = sock:connect("www.google.com", 80)
ngx.say("successfully connected to google!")
--Yes
local sock = ngx.socket.tcp()
local ok, err = sock:connect("www.google.com", 80)
if not ok then
ngx.say("failed to connect to google: ", err)
return
end
ngx.say("successfully connected to google!")
自己編寫的函式,錯誤資訊要作為第二個參數,用字串的格式返回:
--No
localfunction foo()
local ok, err = func()
if not ok then
returnfalse
end
returntrue
end
--No
localfunction foo()
local ok, err = func()
if not ok then
returnfalse, {msg = err}
end
returntrue
end
--Yes
localfunction foo()
local ok, err = func()
if not ok then
returnfalse, "failed to call func(): " .. err
end
returntrue
end