這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
Abstract:
終於要跟go語言沾邊了,到此,作者還有點小小的興奮呢,也不知道為啥!
不管你之前是否從事過web相關的開發,相信你一定聽過【架構】這個詞,不為什麼,因為隨著社會的發展進步,被前人總結出來的架構,經驗等等,系統的、可複用的東西,我們都能認為其為架構。既然說到了架構,那麼毫無疑問,我們這裡要用架構了,不要問我為什麼,因為時間寶貴,我們沒有必要重複造輪子,當然如果你想自己寫架構的話,那我這裡要祝你好運!
平時在工作中會同時寫python和go。截止目前, 用python的時間要比用go的時間要長,各種python架構如django、flask、tornado、scrapy等都有所涉獵。而go的web架構用的還不多,所以在這裡我對go的幾種架構做一個簡單的調研與比較,然後做一個產品選型。
一、 Beego https://beego.me/
架構特性:
- 簡單化:RESTful 支援、MVC 模型,可以使用 bee工具快速地開發應用,包括監控代碼修改進行熱編譯、自動化測試代碼以及自動化打包部署。
- 智能化:支援智能路由、智能監控,可以監控 QPS、記憶體消耗、CPU 使用,以goroutine 的健全狀態,讓您的線上應用盡在掌握。
- 模組化:beego 內建了強大的模組,包括 Session、快取作業、日誌記錄、配置解析、效能監控、上下文操作、ORM模組、請求類比等強大的模組,足以支撐你任何的應用。
- 高效能:beego 採用了 Go 原生的 http 包來處理請求,goroutine 的並發效率足以應付大流量的 Web 應用程式和 API應用,目前已經應用於大量高並發的產品中。
二、 Revel http://revel.github.io/
架構特性:
- 熱編譯:編輯, 儲存, 和 重新整理時,Revel自動編譯代碼和模板,如果代碼編譯錯誤,會給出一個 錯誤提示,同時捕捉 運行期錯誤。
- 全棧功能: Revel 支援: 路由, 參數解析, 驗證, session/flash, 模板, 緩衝, 計劃任務, 測試, 國際化等功能。
- 高效能:Revel 基於 Go HTTP server 構建。 這是techempower發布的 最新評測結果 。在各種不同的情境下進行了多達三到十次的請求負載測試。
- 模組化:Revel架構由被稱為 過濾器 的中介軟體組成,它實現了幾乎所有的請求處理功能。 開發人員可以自由地使用自訂的過濾器,比如如自訂的路由器,用以替換Revel預設的路由過濾器。
三、Martini http://martini.codegangsta.io
其他還有類似Goji,Gin,Traffic,Faygo,essgo, Macaron, GoInk, Baa等等,如果大家有感興趣的可以自己搜來看看。
在本文中,綜合考慮文檔使用廣泛度,文檔的完整度,以及其他各種說不清道不明的原因,本文決定使用Beego架構
安裝: 需要安裝Beego和Bee的開發工具 go get -u github.com/astaxie/beego go get -u github.com/beego/bee
安裝完成之後,在命令列中輸入bee 會有如下輸出:
建立一個新的web項目,項目名稱就簡單叫systemAdmin吧!
看提示可以知道我們已經成功建立了名字叫systemAdmin 的項目,我們來看看初始化的項目的目錄結構:
看這個目錄結構是不是覺得很清晰?是的,確實很清晰,也比較乾淨,不像之前我們初始化的前端代碼,有很多東西。
接下來我們同bee run 運行項目看看:
開啟瀏覽器,我們可以看到,項目已經在http://localhost:8080/ 地址啟動了,接下來我們來看看beego的MVC架構,為我們接下來的開發打好基礎,同時也瞭解一下如果要想實現一個自己的架構,或許我們能從中瞭解到一個架構的設計。
文字描述如下:
在監聽的連接埠接收資料,預設監聽在 8080 連接埠。
使用者請求到達 8080 連接埠之後進入 beego 的處理邏輯。
初始化 Context 對象,根據請求判斷是否為 WebSocket 請求,如果是的話設定 Input,同時判斷請求的方法是否在標準要求方法中(GET、POST、PUT、DELETE、PATCH、OPTIONS、HEAD),防止使用者的惡意偽造請求攻擊造成不必要的影響。
執行 BeforeRouter 過濾器,當然在 beego 裡面有開關設定。如果使用者佈建了過濾器,那麼該開關開啟,這樣可以提高在沒有開啟過濾器的情況下提高執行效率。如果在執行過濾器過程中,responseWriter 已經有資料輸出了,那麼就提前結束該請求,直接跳轉到監控判斷。
開始執行靜態檔案的處理,查看使用者的請求 URL 是否和註冊在靜態檔案處理 StaticDir 中的 prefix 是否匹配。如果匹配的話,採用 http包中預設的 ServeFile 來處理靜態檔案。
如果不是靜態檔案開始初始化 session 模組(如果開啟 session 的話),這個裡面大家需要注意,如果你的 BeforeRouter 過濾器用到了 session 就會報錯,你應該把它加入到 AfterStatic 過濾器中。
開始執行 AfterStatic 過濾器,如果在執行過濾器過程中,responseWriter 已經有資料輸出了,那麼就提前結束該請求,直接跳轉到監控判斷。
執行過過濾器之後,開始從固定的路由規則中尋找和請求 URL 相匹配的對象。這個匹配是全匹配規則,即如果使用者請求的 URL 是 /hello/world,那麼關聯規則中 /hello 是不會匹配的,只有完全符合才算匹配。如果匹配的話就進入邏輯執行,如果不匹配進入下一環節的正則匹配。
正則匹配是進行正則的全匹配,這個正則是按照使用者添加 beego 路由順序來進行匹配的,也就是說,如果你在添加路由的時候你的順序影響你的匹配。和固定匹配一樣,如果匹配的話就進行邏輯執行,如果不匹配進入 Auto 匹配。
如果使用者註冊了 AutoRouter,那麼會通過 controller/method 這樣的方式去尋找對應的 Controller 和他內建的方法,如果找到就開始執行邏輯,如果找不到就跳轉到監控判斷。
如果找到 Controller 的話,那麼就開始執行邏輯,首先執行 BeforeExec 過濾器,如果在執行過濾器過程中,responseWriter 已經有資料輸出了,那麼就提前結束該請求,直接跳轉到監控判斷。
Controller 開始執行 Init 函數,初始化基本的一些資訊,這個函數一般都是 beego.Controller 的初始化,不建議使用者繼承的時候修改該函數。
是否開啟了 XSRF,開啟的話就調用 Controller 的 XsrfToken,然後如果是 POST 請求就調用 CheckXsrfCookie 方法。
繼續執行 Controller 的 Prepare 函數,這個函數一般是預留給使用者的,用來做 Controller 裡面的一些參數初始化之類的工作。如果在初始化中 responseWriter 有輸出,那麼就直接進入 Finish 函數邏輯。
如果沒有輸出的話,那麼根據使用者註冊的方法執行相應的邏輯,如果使用者沒有註冊,那麼就調用 http.Method 對應的方法(Get/Post 等)。執行相應的邏輯,例如資料讀取,資料賦值,模板顯示之類的,或者直接輸出 JSON 或者 XML。
如果 responseWriter 沒有輸出,那麼就調用 Render 函數進行模板輸出。
執行 Controller 的 Finish 函數,這個函數是預留給使用者用來重寫的,用於釋放一些資源。釋放在 Init 中初始化的資訊資料。
執行 AfterExec 過濾器,如果有輸出的話就跳轉到監控判斷邏輯。
執行 Controller 的 Destructor,用於釋放 Init 中初始化的一些資料。
如果這一路執行下來都沒有找到路由,那麼會調用 404 顯示找不到該頁面。
最後所有的邏輯都匯聚到了監控判斷,如果使用者開啟了監控模組(預設是開啟一個 8088 連接埠用於進程內監控),這樣就會把訪問的請求連結扔給監控程式去記錄當前訪問的 QPS,對應的連結訪問的執行時間,請求連結等。
既然瞭解完了整個架構的結構,那麼接下來,我們簡單的實現一下GET/POST請求,作為我們整個項目初始化的練手:
GET /POST: 從前面瞭解到整個架構的入口函數為main.go 路由函數為router.go 所以我們首先需要在router.go中設定好路由 代碼如下:
package routersimport ( "github.com/astaxie/beego" "systemAdmin/controllers")func init() { beego.Router("/", &controllers.MainController{}) beego.Router("/username", &controllers.UserController{}) beego.Router("/login", &controllers.LoginController{})}
設定好了路由,接下來需要去實現Controller,分別為UserController與LoginController,代碼如下:
package controllersimport ( "github.com/astaxie/beego" "strconv" "strings")type MainController struct { beego.Controller}func (c *MainController) Get() { c.Data["Website"] = "magic.chen" c.Data["Email"] = "cfqcsunng@gmail.com" c.TplName = "index.tpl"}// 基本的GET請求擷取使用者名稱type UserController struct { beego.Controller}type Date struct { name string age int sex string}func (c *UserController) Get() { data := Date{"magic", 24, "男"} content := strings.Join([]string{"姓名:" + data.name, "性別:" + data.sex, "年齡:" + strconv.Itoa(data.age)}, " ") c.Ctx.WriteString(content)}// 基本的Post請求type LoginController struct { beego.Controller}func (c *LoginController) Post() { username := c.GetString("username") password := c.GetString("password") content := strings.Join([]string{"使用者名稱:" + username, "密碼:" + password}, " ") c.Ctx.WriteString(content)}
查看訪問結果:
GET:
POST:
post我們用postman工具來測試:
可以看到輸出結果跟我們的輸入一致。ok,這裡簡單的介紹了利用Beego架構初始化一個項目,並簡單實現了兩種最常見的web請求,GET/POST,到此,我們的後端項目初始化工作就算基本完成了,既然前後端的項目都已經搭建ok了,接下來的工作也就真正步入正軌了,在接下來的一系列課程中,我們會詳細的看到,如果進行前後端互動,如何一步步的開發一個完善的企業後台管理系統。
那麼,盡情期待吧!
參考目錄:
- https://beego.me/docs/mvc/
- https://www.zhihu.com/question/27370112
- build-web-application-with-golang