<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          go-tango微內核 Go 語言 Web 框架

          聯(lián)合創(chuàng)作 · 2023-09-20 11:12

          Tango 是微內核可擴展的Go語言Web框架。

          Golang的web框架基本上處于一個井噴期,那么為什么要再造一個輪子。這是因為,目前可擴展性比較強的都是基于函數(shù)作為可執(zhí)行體的,而以結構體作為執(zhí)行體的框架目前可擴展性都不夠強,包括我原先寫的框架xweb也是如此。因此,一個全新的框架出來了,先上地址:https://github.com/lunny/tango。

          初看Tango框架,感覺和Martini及Macaron非常的像。比如這段代碼:

          package main
          
          import "github.com/lunny/tango"
          
          func main() {
              t := tango.Classic()
              t.Get("/", func() string {
                  return "Hello tango!"
              })
              t.Run()
          }

          這種其實大家都支持的。再看這個吧:

          package main        
                      
          import "github.com/lunny/tango"     
                      
          type Action struct {}       
          func (Action) Get() string {        
              return "Hello tango!"       
          }       
                      
          func main() {       
              t := tango.Classic()        
              t.Get("/", new(Action))     
              t.Run()     
          }

          Tango同時支持函數(shù)和結構體作為執(zhí)行體,不過主打是結構體,函數(shù)只作為兼容而用。下面對Tango的各種功能一一道來。

          路由

          Tango目前同時支持3種路由規(guī)則:

          • 靜態(tài)路由

          tg.Get("/", new(Action))		
          • 命名路由

          tg.Get("/:name", new(Action))		

          命名路由對應的參數(shù)內容可通過ctx.Params().Get(":name")來獲得

          • 正則路由

          tg.Get("/(.*)", new(Action))		

          正則路由對應的參數(shù)內容可通過ctx.Params().Get(":0")來獲得

          這里要注意命名路由和正則路由不可混用。

          執(zhí)行體

          同時支持函數(shù)執(zhí)行體和結構體執(zhí)行體,支持的函數(shù)執(zhí)行體形式如下,可以有零個或一個返回值,返回值由Return插件提供,后面會再提:

          func()		
          func(http.ResponseWriter, *http.Request)		
          func(*tango.Context)		
          func(http.Response.Writer)		
          func(*http.Request)		

          同時支持包含Get,Post,Head,Options,Trace,Patch,Delete,Put作為成員方法的結構體作為執(zhí)行體。

          type Action struct {}		
          func (Action) Get() string {		
              return "Get"		
          }		
          			
          func (Action) Post() string {		
              return "Post"		
          }		
          			
          func (Action) Head() string {		
              return "Head"		
          }		
          			
          func (Action) Options() string {		
              return "Options"		
          }		
          			
          func (Action) Trace() string {		
              return "Trace"		
          }		
          			
          func (Action) Patch() string {		
              return "Patch"		
          }		
          			
          func (Action) Delete() string {		
              return "Delete"		
          }		
          			
          func (Action) Put() string {		
              return "Put"		
          }		

          在使用路由時,可以用對應的方法或者Any來加路由:

          t := tango.Classic()		
          t.Get("/1", new(Action))		
          t.Any("/2", new(Action))		

          路由分組

          Tango提供了Group來進行路由分組,Group的最簡單形式如下:

          g := tango.NewGroup()		
          g.Get("/1", func() string {		
              return "/1"		
          })		
          g.Post("/2", func() string {		
              return "/2"		
          })		
          t := tango.Classic()		
          t.Group("/api", g)		

          這樣訪問/api/1就會返回/1,訪問/api/2就會返回/2

          同時也可以這樣:

          t := tango.Classic()		
          t.Group("/api", func(g *tango.Group) {		
              g.Get("/1", func() string {		
                  return "/1"		
              })		
              g.Post("/2", func() string {		
                  return "/2"		
              })		
          })		

          Group也支持子Group:

          t := tango.Classic()		
          t.Group("/api", func(g *tango.Group) {		
              g.Group("/v1", func(cg *tango.Group) {		
                  cg.Get("/1", func() string {		
          	    return "/1"		
          	})		
          	cg.Post("/2", func() string {		
          	    return "/2"		
                  })		
              })		
          })		

          最后,Group也支持邏輯分組:

          o := tango.Classic()		
          o.Group("", func(g *tango.Group) {		
              g.Get("/1", func() string {		
          	return "/1"		
              })		
          })		
          o.Group("", func(g *tango.Group) {		
              g.Post("/2", func() string {		
          	return "/2"		
              })		
          })		

          這樣,即使路由間只是邏輯上分開,而并沒有上級路徑分開,也是可以分成不同的組。

          返回值

          通過前面的例子,我們會發(fā)現(xiàn),所有執(zhí)行體函數(shù),可以有一個返回值或者沒有返回值。Tango的內部插件ReturnHandler來負責根據(jù)函數(shù)的第一個返回值的類型來自動的生成輸出,默認規(guī)則如下:

          • string 返回string,則string會被轉換為bytes并寫入到ResponseWriter,默認狀態(tài)碼為200

          • []byte 返回[]byte, 則會直接寫入ResponseWriter,默認狀態(tài)碼為200

          • error 返回error接口,如果不為nil, 則返回狀態(tài)碼為500,內容為error.Error()

          • AbortError 返回tango.AbortError接口,如果不為nil,則返回狀態(tài)碼為AbortError.Code,內容為AbortError.Error()

          當然了,你可以撰寫你自己的插件來判斷更多的返回值類型。返回值結合tango的一些tricker,可以極大的簡化代碼,比如:

          如果Action結構體包含匿名結構體tango.Json或者tango.Xml,則返回值結果如下:

          如果包含tango.Json匿名結構體,則返回頭的Content-Type會自動設置為:application/json:

          • 如果返回值為error,則返回值為{“err”: err.Error()},狀態(tài)碼為200

          • 如果返回值為AbortError,則返回值為{“err”: err.Error()},狀態(tài)碼為err.Code()

          • 如果返回值為string,則返回值為{“content”: content},狀態(tài)碼為200

          • 如果返回值為[]byte,則返回值為{“content”: string(content)},狀態(tài)碼為200

          • 如果返回值為map,slice,結構體或其它可自動Json化的內容,則返回值為map自動json對應的值,狀態(tài)碼為200

          例如:

          type Action struct {		
              tango.Json		
          }		
          var i int		
          func (Action) Get() interface{} {		
              if i == 0 {		
                  i = i + 1		
          	return map[string]interface{}{"i":i}		
              }		
              return errors.New("could not visit")		
          }		
          func main() {		
              t := tango.Classic()		
              t.Any("/", new(Action))		
              t.Run()		
          }		

          以上例子,訪問時會始終返回json,第一次訪問會返回map,第二次返回error。(注:這里只是演示代碼,實際執(zhí)行i必須加鎖)

          Compress

          Tango擁有一個默認的壓縮中間件,可以按照擴展名來進行文件的壓縮。同時,你也可以要求某個Action自動或強制使用某種壓縮。比如:

          type CompressExample struct {		
              tango.Compress // 添加這個匿名結構體,要求這個結構體的方法進行自動檢測壓縮		
          }		
          func (CompressExample) Get() string {		
              return fmt.Sprintf("This is a auto compress text")		
          }		
          o := tango.Classic()		
          o.Get("/", new(CompressExample))		
          o.Run()		

          以上代碼默認會檢測瀏覽器是否支持壓縮,如果支持,則看是否支持gzip,如果支持gzip,則使用gzip壓縮,如果支持deflate,則使用deflate壓縮。

          type GZipExample struct {		
              tango.GZip // add this for ask compress to GZip, if accept-encoding has no gzip, then not compress		
          }		
          func (GZipExample) Get() string {		
              return fmt.Sprintf("This is a gzip compress text")		
          }		
          o := tango.Classic()		
          o.Get("/", new(GZipExample))		
          o.Run()		

          以上代碼默認會檢測瀏覽器是否支持gzip壓縮,如果支持gzip,則使用gzip壓縮,否則不壓縮。

          type DeflateExample struct {		
              tango.Deflate // add this for ask compress to Deflate, if not support then not compress
          }		
          func (DeflateExample) Get() string {		
              return fmt.Sprintf("This is a deflate compress text")		
          }		
          o := tango.Classic()		
          o.Get("/", new(DeflateExample))		
          o.Run()		

          以上代碼默認會檢測瀏覽器是否支持deflate壓縮,如果支持deflate,則使用deflate壓縮,否則不壓縮。

          Static

          Static 讓你用一行代碼可以完成一個靜態(tài)服務器。

          func main() {		
              t := tango.New(tango.Static())
              t.Run()		
          }		

          然后,將你的文件放到 ./public 目錄下,你就可以通過瀏覽器放問到他們。比如:

          http://localhost/images/logo.png  --> ./public/images/logo.png		

          當然,你也可以加入你basicauth或者你自己的認證中間件,這樣就變?yōu)榱艘粋€私有的文件服務器。

          func main() {		
              t := tango.New()		
              t.Use(AuthHandler)		
              t.Use(tango.Static())		
              t.Run()		
          }		

          Handler

          Handler 是tango的中間件。在tango中,幾乎所有的事情都由中間件來完成。撰寫一個你自己的中間件非常簡單,并且我們鼓勵您只加載需要的中間件。

          tango的中間件只需要符合以下接口即可。

          type Handler interface {		
              Handle(*tango.Context)		
          }		

          同時,tango也提供了tango.HandlerFunc,以方便你將一個函數(shù)包裝為中間件。比如:

          func MyHandler() tango.HandlerFunc {		
              return func(ctx *tango.Context) {		
                  fmt.Println("this is my first tango handler")		
          	ctx.Next()		
              }		
          }		
          t := tango.Classic()		
          t.Use(MyHandler())		
          t.Run()		

          正常的形式也可以是:

          type HelloHandler struct {}		
          func (HelloHandler) Handle(ctx *tango.Context) {		
              fmt.Println("before")		
              ctx.Next()		
              fmt.Println("after")		
          }		
          t := tango.Classic()		
          t.Use(new(HelloHandler))		
          t.Run()		

          當然,你可以直接將一個包含tango.Context指針的函數(shù)作為中間件,如:

          tg.Use(func(ctx *tango.Context){		
              fmt.Println("before")		
              ctx.Next()		
              fmt.Println("after")		
          })		

          為了和標準庫兼容,tango通過UseHandler支持http.Handler作為中間件,如:

          tg.UseHandler(http.Handler(func(resp http.ResponseWriter, req *http.Request) {		
          }))		

          老的中間件會被action被匹配之前進行調用。

          Call stack

          以下是中間件的調用順序圖:

          tango.ServeHttp		
          	|--Handler1		
          		|--Handler2		
          			|-- ...HandlerN		
          			        |---Action(If matched)		
          			...HandlerN--|		
          		Handler2 ----|		
          	Handler1--|		
          (end)--|		

          在中間件中,您的中間件代碼可以在Next()被調用之前或之后執(zhí)行,Next表示執(zhí)行下一個中間件或Action被執(zhí)行(如果url匹配的話)。如果不調用Next,那么當前請求將會被立即停止,之后的所有代碼將不會被執(zhí)行。

          注入

          更多的注入方式參見以下示例代碼:

          Request

          type Action struct {		
              tango.Req		
          }		

          Response

          type Action struct {		
              tango.Resp		
          }		

          Context

          type Action struct {		
              tango.Ctx		
          }		

          Logger

          type Action struct {		
              tango.Log		
          }		

          Params

          type Action struct {		
              tango.Params		
          }		

          Json

          type Action struct {		
              tango.Json		
          }		

          Xml

          type Action struct {		
              tango.Xml		
          }		

          第三方插件

          目前已經(jīng)有了一批第三方插件,更多的插件正在陸續(xù)開發(fā)中,歡迎大家進行貢獻:

          • session - Session管理

          • xsrf - 生成csrf token和進行校驗

          • bind - 自動綁定參數(shù)到結構體

          • renders - Go模板引擎插件

          • dispatch - 多應用支持

          • tpongo2 - Pongo2 模板引擎支持

          • captcha - 驗證碼插件

          • events - 事件插件

          • flash - 在requests之間共享數(shù)據(jù)

          案例

          • Wego - golanghome.com論壇的修改版

          • ABlog - 一個新型博客

          瀏覽 45
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          編輯 分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          編輯 分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  欧美 日韩 中文 | 午夜操一操一级 | 国产一卡二卡免费看 | 国产 无码 精品 | 人人操人人网站 |