從本章開始假設大家都熟悉lua語法.
運行流程
在上一章節學會了如何安裝cf後, 本章節就會介紹cf到運行機制與httpd的server搭建!
cf是一個非常典型的基於協程的事件驅動開發框架在封裝成API後, 可以依賴事件循環執行一套穩定運行時環境.
而lua本身提供了強大的table
數據結構可以根據需要自行構建所謂的"config", 所以cf爲了減少無用的依賴就沒有提供額外的config文件進行配置.
cf會假設所有業務代碼文件都在script
目錄下, 所以建議您在script
下自行劃分好文件的目錄歸屬.
cf將所有業務編寫的腳本目錄命名爲script
, script
目錄下點main.lua
文件將會是入口文件. 這個main.lua
執行完畢之後纔會真正進入事件循環.
在執行完成script/main.lua
文件後, cf則會是實際情況決定是否需要開始運行事件循環. 假設開發者僅僅想運行print("hello world")
, 那麼cf將會在main.lua
執行完成後直接退出.
運行機制的問題與模塊化的設計
main.lua
文件內部可以導入其它lua代碼進行模塊化設計, 但是有一點需要注意的是: cf框架在使用require
導入文件時, 導入的文件只能用於定義不可用於流程執行.
什麼意思呢? 例如, 當你在使用創建一個httpd實例之前會先創建DB對象並且進行初始化! 這時候您可以回設計像下面的代碼:
-- mydb.lua
local DB = require "DB"
local db = DB:new {
host = "localhost",
port = 3306,
database = "cfadmin",
charset = 'utf8'
-- ...
}
local ok = db:connect()
if not ok then
return nil
end
return db
-- main.lua
local db_cls = require "mydb"
--[[
... do your want do
]]
這樣做你會得到一個錯誤提示:"attempt to yield from outside a coroutine", 這個錯誤提示的中文大概意思就是: "不能在非協程的環境下切換執行權".
這是因爲require函數的對指定的腳本調用的Call方法使其不允許臨時切換出執行權, 而初始化數據庫連接操作是依賴cf的協程與異步操作所以就會導致上面的錯誤出現.
可以將mydb.lua與main.lua的代碼替換成下面這樣(Cache庫同理)來解決:
-- mydb.lua
local DB = require "DB"
local db
return function ()
if db then
return db
end
db = DB:new {
host = "localhost",
port = 3306,
database = "cfadmin",
charset = 'utf8'
-- ...
}
local ok = db:connect()
if not ok then
db:close()
db = nil
return nil, "連接失敗"
end
return db
end
-- main.lua
local get_db = require "mydb"
local db = get_db()
-- [[
... do your want do
]]
這是用一種巧妙的function與upvalue的方式避開了require的內部call調用, require返回後執行權重新回到了由cf啓動的協程中. 這樣就可以開始正確初始化了.
這種情況僅限於依賴require執行某段異步代碼塊的時候, 其它情況下一般不會出現問題. 優質的項目管理人員一般不會出現這樣的設計.
使用httpd庫快速搭建lua web開發環境
httpd庫是cf內置的基於http 1.1協議開發的web server! 高效解析器是必不可少的, httpd庫使用picohttpparser解析器來構建http context.
我們假設您至少看過httpd庫的API Reference, 並且至少知道下面所述的API.
此處所有的API與使用方式都將會在API Reference中找到.
1. 導入http庫
httpd庫位於app/lualib
下, 使用者可以在main.lua
文件內直接使用local httpd = require "httpd"
導入httpd庫.
2. 初始化一個httpd app對象
httpd庫使用lua class對象進行創建! 默認提供了new方法, 使用者可以使用new方法創建一個httpd的app實例.
local httpd = require "httpd"
local app = httpd:new("app")
3. 註冊靜態文件路徑
httpd提供給了內置的靜態文件查找能力, 只需要使用者自動使用static方法註冊靜態文件路徑即可.
app:static("static", 30)
static表示使用者想將app/static
文件夾當做靜態文件的根目錄.
4. 設置監聽端口
httpd啓動需要指定監聽的端口, 默認監聽所有網卡. 雖然沒有使用第一個參數, 但是不可爲空.
app:listen("0.0.0.0", 8080)
5. 運行
在初始化完成後, app調用run
方法將會啓動httpd服務器. run
方法後面的代碼可能永遠不會有機會執行.
app:run()
6. 運行cf
使用./cfadmin
命令運行httpd server, 如果您看到類似運行
等字樣說明httpd服務已經啓動完成, 否則將會有響應的錯誤提示.
7. 完整的代碼示例
-- script/main.lua
local httpd = require "httpd"
local app = httpd:new("app")
app:static("static", 30)
app:listen("0.0.0.0", 8080)
app:run()
體驗一下
現在, 讓我們打開http://localhost:8080/index.html
查看是否能正確顯示頁面了呢?
更多的httpd API
在這裏你可以找到更多有關httpd庫的API說明.
繼續學習
一下章我們一起學習如何用cf來註冊註冊路由