1.常見框架
1.1 框架排名
- Gin 31k [Lite]
- Beego 22k
- Iris 16k
- Echo 15k [Lite]
- Revel 11k
- Martini 10k [×]
- buffalo 5k [Lite]
1.2 框架特性
Gin:
Gin 是一個用 Go (Golang) 編寫的 web 框架。它是一個類似於 martini 但擁有更好性能的 API 框架, 由於 httprouter,速度提高了近 40 倍。如果你是性能和高效的追求者, 你會愛上 Gin.
快速:基於 Radix 樹的路由,小內存占用。沒有反射。可預測的 API 性能。
支持中間件:傳入的 HTTP 請求可以由一系列中間件和最終操作來處理。例如:Logger,Authorization,GZIP,最終操作 DB。
Crash 處理:Gin 可以 catch 一個發生在 HTTP 請求中的 panic 並 recover 它。這樣,你的服務器將始終可用。例如,你可以向 Sentry 報告這個 panic!
JSON 驗證:Gin 可以解析並驗證請求的 JSON,例如檢查所需值的存在。
路由組:更好地組織路由。是否需要授權,不同的 API 版本…… 此外,這些組可以無限制地嵌套而不會降低性能。
錯誤管理:Gin 提供了一種方便的方法來收集 HTTP 請求期間發生的所有錯誤。最終,中間件可以將它們寫入日志文件,數據庫並通過網絡發送。
內置渲染:Gin 為 JSON,XML 和 HTML 渲染提供了易於使用的 API。
可擴展性:新建一個中間件非常簡單,去查看示例代碼吧。
Beego:
bee 工具是一個為了協助快速開發 beego 項目而創建的項目,通過 bee 您可以很容易的進行 beego 項目的創建、熱編譯、開發、測試、和部署。
簡單化:RESTful 支持、MVC 模型,可以使用 bee 工具快速地開發應用,包括監控代碼修改進行熱編譯、自動化測試代碼以及自動化打包部署。
智能化:支持智能路由、智能監控,可以監控 QPS、內存消耗、CPU 使用,以及 goroutine 的運行狀況,讓您的線上應用盡在掌握。
模塊化:beego 內置了強大的模塊,包括 Session、緩存操作、日志記錄、配置解析、性能監控、上下文操作、ORM 模塊、請求模擬等強大的模塊,足以支撐你任何的應用。
高性能:beego 采用了 Go 原生的 http 包來處理請求,goroutine 的並發效率足以應付大流量的 Web 應用和 API 應用,目前已經應用於大量高並發的產品中。
Iris:
- 專注於高性能
- 簡單流暢的API
- 高擴展性
- 強大的路由和中間件生態系統
- 使用iris獨特的表達主義路徑解釋器構建RESTful API
- 動態路徑參數化或通配符路由與靜態路由不沖突
- 使用重定向選項從URL中刪除尾部斜杠
- 使用虛擬主機和子域名變得容易
- 分組API和靜態或甚至動態子域名
- net / http和negroni-like處理程序通過iris.FromStd兼容
- 針對任意Http請求錯誤 定義處理函數
- 支持事務和回滾
- 支持響應緩存
- 使用簡單的函數嵌入資源並與go-bindata 保持兼容
- mvc
- 上下文
- 高度可擴展的試圖渲染(目前支持markdown,json,xml,jsonp等等)
- 正文綁定器和發送HTTP響應的便捷功能
- 限制請求正文
- 提供靜態資源或嵌入式資產
- 本地化i18N
- 壓縮(Gzip是內置的)
- 身份驗證
- Basic Authentication
- OAuth, OAuth2 (支持27個以上的熱門網站)
- JWT 服務器
- 通過TLS提供服務時,自動安裝和提供來自https://letsencrypt.org的證書
- 默認為關閉狀態
- 在關閉,錯誤或中斷事件時注冊
- 連接多個服務器,完全兼容 net/http#Server
- 視圖系統.支持五種模板引擎 完全兼容 html/template
- Websocket庫,其API類似於http://socket.io [如果你願意,你仍然可以使用你最喜歡的]
- 熱重啟
- Typescript集成 + Web IDE
- Iris是最具特色的網絡框架之一
1.3 性能測試
- (1):在一定的時間內實現的總調用數,越高越好
- (2):單次操作耗時(ns/op),越低越好
- (3):堆內存分配 (B/op), 越低越好
- (4):每次操作的平均內存分配次數(allocs/op),越低越好
2.應用
2.1 主機服務
Gin
Gin 擁有靈活的開發環境,在運行時可以選擇默認的服務器來運行,也可以選擇原生的http.ListenAndServe(":8080", router)
來開啟服務,這是因為其本身使用 gin.Default()
創建的 router
對象實現了 Handler 接口,這就以為着其可以選擇其他的 HTTP 服務器,如 fvbock/endless 、 manners 或者原生的 http.Server 內置的 Shutdown 方法進行服務重啟。
r := gin.Default() _ = r.Run() // 或者啟動原生服務 manners.ListenAndServe(":8888", r)
BeeGo
Beego 提供了一個構建工具,有着標准的開發環境規范,可以一鍵生成工程目錄,並在工程目錄使用 run
指令可以直接運行項目,並且支持開發模式下的熱更新。
beego.Run()
Iris
Iris 的主機有多種拓展功能,包括自定義監聽服務、主機配置,同時也支持多主機服務。與 Gin 相似的 iris.Router與 net/http/Handler 功能兼容,它可以在任何net/http服務器上進行調整:
app := iris.New() app.Run(iris.Addr(":8080")) // 或者自定義鏈接方式與端口號 l, err := listenerCfg.NewListener("tcp", ":8080") if err != nil { app.Logger().Fatal(err) } app.Run(iris.Listener(l)) // 或者啟動原生服務 app.Run(iris.Raw(&http.Server{Addr:":8080"}).ListenAndServe)
2.2 路由
Gin
Gin 在路由系統上集成了 HttpRouter 擁有高性能的優勢,同時擁有其豐富的功能,包括組合路由、路由驗證、CORS 等。
簡單路由:
r := gin.Default() r.GET("/ping", func(c *gin.Context) { c.String(http.StatusOK, "pong") })
分層路由:
someGroup := router.Group("/someGroup") { someGroup.GET("/someGet", getting) someGroup.POST("/somePost", posting) }
BeeGo
BeeGo 的路由功能較為豐富,擁有基礎路由、固定路由、正則路由、注解路由、namespace等多個功能,其 REST 風格性較強,且有固定的路由層規范。
簡單路由:
beego.Get("/",func(ctx *context.Context){ ctx.Output.Body([]byte("hello world")) })
固定路由:
beego.Router("/", &controllers.MainController{}) beego.Router("/admin", &admin.UserController{}) beego.Router("/admin/index", &admin.ArticleController{}) beego.Router("/admin/addpkg", &admin.AddController{})
namespace(分層路由):
//初始化 namespace ns := beego.NewNamespace("/v1", beego.NSCond(func(ctx *context.Context) bool { if ctx.Input.Domain() == "api.beego.me" { return true } return false }), beego.NSBefore(auth), beego.NSGet("/notallowed", func(ctx *context.Context) { ctx.Output.Body([]byte("notAllowed")) }), beego.NSRouter("/version", &AdminController{}, "get:ShowAPIVersion"), beego.NSRouter("/changepassword", &UserController{}), beego.NSNamespace("/shop", beego.NSBefore(sentry), beego.NSGet("/:id", func(ctx *context.Context) { ctx.Output.Body([]byte("notAllowed")) }), ), beego.NSNamespace("/cms", beego.NSInclude( &controllers.MainController{}, &controllers.CMSController{}, &controllers.BlockController{}, ), ), ) //注冊 namespace beego.AddNamespace(ns)
Irisi
簡單路由:
app.Get("/", func(ctx iris.Context) { ctx.HTML("<h1> Hello from /contact </h1>") })
分層路由:
users := app.Party("/users", myAuthMiddlewareHandler) // http://localhost:8080/users/42/profile users.Get("/{id:int}/profile", userProfileHandler) // http://localhost:8080/users/inbox/1 users.Get("/inbox/{id:int}", userMessageHandler) // 或者使用嵌套風格 app.PartyFunc("/users", func(users iris.Party) { users.Use(myAuthMiddlewareHandler) // http://localhost:8080/users/42/profile users.Get("/{id:int}/profile", userProfileHandler) // http://localhost:8080/users/messages/1 users.Get("/inbox/{id:int}", userMessageHandler) })
2.3 上下文對象
在進行路由匹配之后,可以獲取到上下文對象,三套框架都對 Context 進行了封裝。
Gin 與 Iris 對 context 的封裝均是為其增加了必要的新功能,同時可以返回原生的http.Request
對象。但 Beego 的 context 模塊是對原生的 http.ResponseWriter
和 http.Request
對象進行了徹底的封裝,將其分為兩個部分,分別為 Input 對象與 Output 對象,對應的將常用方法進行封裝,並不能調出原生的對象。
2.4 數據操作
原生
在原生開發中,Go 支持解析 JSON 格式的數據處理能力:
// 解析 JSON func Unmarshal(data []byte, v interface{}) error // 生成 JSON func Marshal(v interface{}) ([]byte, error)
如果使用simplejson
可以簡化 JSON 數據的操作:
js, err := NewJson([]byte(`{ "test": { "array": [1, "2", 3], "int": 10, "float": 5.150, "bignum": 9223372036854775807, "string": "simplejson", "bool": true } }`)) arr, _ := js.Get("test").Get("array").Array() i, _ := js.Get("test").Get("int").Int() ms := js.Get("test").Get("string").MustString()
Gin
Gin 可以使用 c.ShouldBind
方法,可以將參數自動綁定到 struct
.該方法是會檢查 Url 查詢字符串和 POST 的數據,而且會根據 content-type
類型,優先匹配JSON
或者 XML
,之后才是 Form
。
接收數據:
func main() { route := gin.Default() route.POST("/testing", (c *gin.Context) { var person Person // 定義結構體步驟省略 // 綁定到 person if c.ShouldBind(&person) == nil { log.Println(person.Name) log.Println(person.Address) log.Println(person.Birthday) } c.String(200, "Success") }) route.Run(":8085") }
發送數據:
Gin 輸出這 JSON、 XML、 YAML 三種格式非常方便,直接使用對用方法並賦值一個結構體給它就行了。
同時還可以使用gin.H
。gin.H
是一個很巧妙的設計,你可以像javascript
定義json
一樣,直接一層層寫鍵值對,只需要在每一層加上 gin.H
即可:
func main() { r := gin.Default() // gin.H 本質是 map[string]interface{} r.GET("/someJSON", func(c *gin.Context) { // 會輸出頭格式為 application/json; charset=UTF-8 的 json 字符串 c.JSON(http.StatusOK, gin.H{"message": "hey", "status": http.StatusOK}) }) r.GET("/moreJSON", func(c *gin.Context) { // 直接使用結構體定義 var msg struct { Name string `json:"user"` Message string Number int } msg.Name = "Lena" msg.Message = "hey" msg.Number = 123 // 會輸出 {"user": "Lena", "Message": "hey", "Number": 123} c.JSON(http.StatusOK, msg) }) r.GET("/someXML", func(c *gin.Context) { // 會輸出頭格式為 text/xml; charset=UTF-8 的 xml 字符串 c.XML(http.StatusOK, gin.H{"message": "hey", "status": http.StatusOK}) }) r.GET("/someYAML", func(c *gin.Context) { // 會輸出頭格式為 text/yaml; charset=UTF-8 的 yaml 字符串 c.YAML(http.StatusOK, gin.H{"message": "hey", "status": http.StatusOK}) }) r.Run(":8080") }
Gin 支持返回的數據格式有:HTML, String,JSON, XML, YAML
BeeGo
Beego 對與JSON 數據處理則比較復雜,如果接受數據則需要從 context.RequestBody
中取出數據,之后需要使用斷言解析數據,實際上,這里的處理方式與原生的是一樣的,並未進行功能優化:
var body map[string]interface{} _ = json.Unmarshal(ctx.Input.RequestBody, &body) // 將 json 數據解析到 body 變量中 username := body["name"].(string) // 使用斷言取出單個數據
對於返回一個 json 數據,BeeGo 只是將我們創建的 json 結構對象存放於context.Data
下的“json”
字段中,然后調用context.ServeJSON()
方法時,會去獲取c.Data["json"]
下存放的結構然后將結果轉換成 json 的數據格式並發送:
type User struct { Name string `json:"name"` Age int `json:"age"` } func (c *TestController) TestData() { user := User{ Name: "huahua", Age: 18, } c.Data["json"] = user c.ServeJSON() }
起始在處理 json 這一步,Beego 只是做了非常簡單的替換工作,context.ServeJSON()
的方法調用后,取到我們設置的結構體后調用了:
func (output *BeegoOutput) JSON(data interface{}, hasIndent bool, encoding bool) error
該方法將結構體通過 json.Marshal()
轉成了 json 格式,同時又為響應報文添加了相應響應數據格式信息,之后將數據送出。
此外,BeeGo 支持返回的數據類型由有:JSON、XML、JSONP
Iris
Irisi 對處理 JSON 數據的方法進行了封裝,同時也擁有驗證數據的能力。
發送數據與前兩者無差別,都是先定義結構體,然后底層使用 JSON 庫的能力對 JSON 數據進行解析並賦值於創建的對象。
接收數據:
func MyHandler(ctx iris.Context) { var c Company // 定義結構體省略 if err := ctx.ReadJSON(&c); err != nil { ctx.StatusCode(iris.StatusBadRequest) ctx.WriteString(err.Error()) return } ctx.Writef("Received: %#+v\n", c) }
在對於返回數據的處理上,與 Gin 相似,采用了在 iris.Context.JSON()
方法可以將對象轉化為 JSON 數據輸出。
返回數據:
app.Get("/encode", func(ctx iris.Context) { peter := User{ Firstname: "John", Lastname: "Doe", City: "Neither FBI knows!!!", Age: 25, } //手動設置內容類型: ctx.ContentType("application/javascript") ctx.JSON(peter) })
此外,Iris 支持返回的數據格式有:binary, text, json, jsonp, xml, markdown
2.5 模板引擎
原生
Go web 能力中包含了模板引擎的支持,可以使用 template
包來進行模板處理,使用類似 Parse
、ParseFile
、Execute
等方法從文件或者字符串加載模板,然后執行類似下圖展示的模板的 merge 操作:
func handler(w http.ResponseWriter, r *http.Request) { t := template.New("some template") // 創建一個模板 t, _ = t.ParseFiles("tmpl/welcome.html") // 解析模板文件 user := GetUser() // 獲取當前用戶信息 t.Execute(w, user) // 執行模板的 merger 操作 }
原生的模板引擎支持以下的能力:
- 字段操作:
{{.}}
- 數據遍歷:
{{with …}}…{{end}} {{range …}}{{end}}
- 條件處理:
if ... else ...
- 管道符 (基於模板函數)
- 模板函數
- 模板變量
- Must 操作:作用是檢測模板是否正確,例如大括號是否匹配,注釋是否正確的關閉,變量是否正確的書寫。
- 嵌套模板
Gin
Gin 可以通過配置 LoadHTMLGlob()
或者 LoadHTMLFiles()
啟用模板渲染,這兩個方法掛載與 gin.Defalut()
生成的 router 對象上,用於設置,模板目錄 。匹配完成后可以調用 Context.HTML
進行渲染和數據注入。
同時,與原生不同的是,Gin 可以使用 gin.H()
來向模板注入 json 格式的數據,而不需要創建額外的結構體。
func main() { router := gin.Default() router.LoadHTMLGlob("templates/*") //router.LoadHTMLFiles("templates/template1.html", "templates/template2.html") router.GET("/index", func(c *gin.Context) { c.HTML(http.StatusOK, "index.tmpl", gin.H{ "title": "Main website", }) }) router.Run(":8080") }
Gin 的模板引擎支持以下能力:
- 使用自定義的 html 模板渲染
- 自定義分隔符(模板標簽)
- 繼承原生能力
相比原生,Gin 定義模板的方式是采用創建全局模板對象(LoadHTMLGlob),然后在上下文對象中使用 c.HTML
去直接調用模板路徑下的文件渲染模板。而原生則是在路由的上下文對象中創建 Template 對象,然后在上下文對象中渲染 Template 對象完成渲染工作。
Beego
beego 的模板處理引擎采用的是 Go 內置的 html/template
包進行處理,而且 beego 的模板處理邏輯是采用了緩存編譯方式,也就是所有的模板會在 beego 應用啟動的時候全部編譯然后緩存在 map 里面,Beego 的模板引擎支持以下能力:
- 自定義模板目錄
- 自動渲染
- 自定義模板標簽
- 模板數據:模板中的數據是通過在 Controller 中 this.Data 獲取的
- 自定義模板名稱
- layout 設計、LayoutSection:實際上是模板的組合、嵌套
- renderform
Iris
Iris 自身並沒有創建一種直接可用的模板引擎,而是交給用戶可以選擇任意一種模板引擎,且完全兼容 html/template。
官方推薦使用 Hero 引擎,可以預編譯html
模板以獲取代碼,其擁有以下特性:
- 高性能.
- 非常易用.
- 功能強大,支持模板繼承和模板include.
- 自動編譯.
同時可以選用 quicktemplate 引擎,其擁有以下特性:
- 非常快。模板轉換為Go代碼然后編譯
Quicktemplate
語法非常接近Go
- 在開始使用quicktemplate
之前無需學習另一種模板語言- 在模板編譯期間幾乎所有錯誤都被捕獲,因此生產受模板相關錯誤的影響較小
- 使用方便。有關詳細信息,請參閱快速入門和示例
- 強大。任意
Go
代碼可以嵌入到模板中並與模板混合。小心這個功能 - 不要從模板中查詢數據庫and/or
外部資源,除非你錯過Go中的PHP
方式:)
這種功能主要用於任意數據轉換 - 易於使用的模板繼承由
Go
接口提供支持。請參閱此示例以獲取詳細信 - 模板被編譯為單個二進制文件,因此無需將模板文件復制到服務器
2.6 MVC 架構
Gin
Gin 不支持 MVC 架構模式,需要開發者自行實現,具有一定的靈活性。
Beego
Beego 是標准的 MVC 框架,對 MVC 有着良好的支持,同時提供了 Model 層的 ORM 引擎。
Iris
Iris對MVC(模型視圖控制器)模式有一流的支持,Iris web框架支持請求數據、模型、持久數據和以最快的速度執行的綁定。其模式流程圖如下: