溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

golang中beego的示例分析

發(fā)布時間:2021-12-15 09:39:47 來源:億速云 閱讀:195 作者:小新 欄目:大數(shù)據(jù)

這篇文章主要介紹golang中beego的示例分析,文中介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們一定要看完!

1.http.HandleFunc將pattern及我們自定義的handler存儲在DefaultServeMux的一個map中。

2.當http.ListenAndServe的handler為nil時,系統(tǒng)會從DefaultServeMux存儲信息的map中匹配pattern獲取對應的handler,進而處連接請求。

如果用更簡單的話來總結以上兩條,就是:路由的存儲與匹配

beego作為一個基于golang之上的框架(此處只討論核心http及路由部分的處理),必然脫離不了語言底層的支持。因此,我們可以大膽猜測,beego的路由處理主要是在HandleFunc的封裝上,即如何更好的封裝HandlerFunc且便于使用,這應該也是beego支持多種路由方式的特點了。

一、beego.Run

我們先從源碼來驗證一條簡單的猜測,beego基于http.ListenAndServe來處理網絡請求(本次僅針對http協(xié)議的處理進行分析,https協(xié)議類似)。

beego.Run()->BeeApp.Run()

// Run beego application.

func (app *App) Run() {

    ...

    app.Server.Handler = app.Handlers

    app.Server.ReadTimeout = time.Duration(BConfig.Listen.ServerTimeOut) * time.Second

    app.Server.WriteTimeout = time.Duration(BConfig.Listen.ServerTimeOut) * time.Second

    app.Server.ErrorLog = logs.GetLogger("HTTP")

    // run graceful mode

    if BConfig.Listen.Graceful {

        httpsAddr := BConfig.Listen.HTTPSAddr

        app.Server.Addr = httpsAddr

        if BConfig.Listen.EnableHTTPS {

            go func() {

                ...

                if err := server.ListenAndServeTLS(BConfig.Listen.HTTPSCertFile, BConfig.Listen.HTTPSKeyFile); err != nil {

                    logs.Critical("ListenAndServeTLS: ", err, fmt.Sprintf("%d", os.Getpid()))

                    time.Sleep(100 * time.Microsecond)

                    endRunning <- true

                }

            }()

        }

        if BConfig.Listen.EnableHTTP {

            go func() {

                ...

                if err := server.ListenAndServe(); err != nil {

                    logs.Critical("ListenAndServe: ", err, fmt.Sprintf("%d", os.Getpid()))

                    time.Sleep(100 * time.Microsecond)

                    endRunning <- true

                }

            }()

        }

        <-endRunning

        return

    }

    ...

}

http.ListenAndServe的源碼如下:

func ListenAndServe(addr string, handler Handler) error {

    server := &Server{Addr: addr, Handler: handler}

    return server.ListenAndServe()

}

可以很明顯的看出beego最終和http.ListenAndServe調用的接口是一樣的。(此處只對http部分進行分析,https協(xié)議也是通用的只是調用的接口是ListenAndServeTLS)

二、Router

1.支持的路由方式

根據(jù)官網的描述,beego支持以下路由方式:

基礎路由

beego.Get

beego.Post

自定義的 handler 實現(xiàn)

s := rpc.NewServer()

s.RegisterCodec(json.NewCodec(), "application/json")

s.RegisterService(new(HelloService), "")

beego.Handler("/rpc", s)

固定路由&正則路由&自定義方法

// 固定路由

beego.Router("/", &controllers.MainController{})

beego.Router("/admin", &admin.UserController{})

// 正則路由

beego.Router("/api/?:id", &controllers.RController{})

beego.Router("/cms_:id([0-9]+).html", &controllers.CmsController{}))

// 指定方法

beego.Router("/api/list",&RestController{},"*:ListFood")

beego.Router("/api/create",&RestController{},"post:CreateFood")

自動匹配路由

beego.AutoRouter(&controllers.ObjectController{})

-注解路由

// @router /all/:key [get]

func (this *CMSController) AllBlock() {

}

beego.Include(&CMSController{})

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)

NSNamespace/NewNamespace內部的部分存儲路由時,只處理了自身的路由,總的路由還需要在NSNamespace/NewNamespace進行添加prefix,最終存儲在BeeApp.Handlers.routers.

數(shù)據(jù)傳輸在此進行:

    app.Server.Handler = app.Handlers

    app.Server.ReadTimeout = time.Duration(BConfig.Listen.ServerTimeOut) * time.Second

    app.Server.WriteTimeout = time.Duration(BConfig.Listen.ServerTimeOut) * time.Second

    app.Server.ErrorLog = logs.GetLogger("HTTP")

在此,我們研究下幾個主要入口作為示例來分析源碼。

2.具體路由方式的分析

在初探中我們只做簡單的功能分析,具體的分析我們在后續(xù)的文章中加以補充。

(1)beego.Get

beego.Get->BeeApp.Handlers.Get->p.AddMethod->p.addToRouter

其中p即BeeApp.Handlers,因此這一連串的操作主要是將router信息存入BeeApp.Handlers中。

(2)beego.Router

beego.Router->BeeApp.Handlers.Add->p.addWithMethodParams->p.addToRouter

與(1)同理

(3)beego.AutoRouter

beego.AutoRouter->BeeApp.Handlers.AddAuto->p.AddAutoPrefix->p.addToRouter

與(1)同理

(4)beego.Include

beego.Include->BeeApp.Handlers.Include->p.addWithMethodParams->p.addToRouter

與(1)同理

(5)beego.AddNamespace

beego.AddNamespace->BeeApp.Handlers.routers[k]

直接將namespace.handlers.routers中的添加前綴后存入BeeApp.Handlers.routers中。

AddNamespace、NSNamespace及其內部的一系列NSNamespace方法集最終依然調用n.handlers的方法集中,然后經過AddNamespace,保存至BeeApp.Handlers中

三、ServeHTTP

既然處理請求時,經過了http.ListenAndServe,根據(jù)我們對ListenAndServe的分析,最終請求會交由server.Handler的ServeHTTP來處理。beego中的Handler即為BeeApp.Handlers,其類型是ControllerRegister,也就是說請求最終交由ControllerRegister的ServeHTTP實現(xiàn)來處理。此處我們也是只談下處理過程,具體的細節(jié)我們在之后的分析文章內細談。

三、總結

我們分別從兩個入口beego.Run、router兩個入口的使用,可以看到beego處理的邏輯基本上和golang底層http.ListenAndServe、http.HandleFunc的原理一致,只是有更高層次的封裝,以及更便利的路由聲明及處理。在后續(xù)的文章中我們會對beego的處理作進一步的分析。

最后,我們可以做下幾點簡單的總結:

(1)routers package主要是生成路由及處理的相關信息,并保存至BeeApp.Handler中,

(2)beego.Run則是帶著BeeApp.Handler的啟動http的服務,

(3)接收請求后,由BeeApp.Handler的ServeHTTP進行處理,作出對應響應。

實際上beego的入口只有beego.Run,怎么與routers具體聯(lián)系起來的呢?

1

接下來我們一步步看下beego.Run背后的邏輯。

一、import & init

我們首先從程序最開始的import部分開始看。

import (

    _ "test/routers"

    "github.com/astaxie/beego"

)

我們知道golang的初始化的方向如下:

按照這個方向,我們可以知道先調用routers package init,在routers內再次import “github.com/astaxie/beego”,因此先調用beego package init,然后調用routers package init。

1.beego init

代碼如下:

var (

    // BeeApp is an application instance

    BeeApp *App

)

func init() {

    // create beego application

    BeeApp = NewApp()

}

func NewApp() *App {

    cr := NewControllerRegister()

    app := &App{Handlers: cr, Server: &http.Server{}}

    return app

}

func NewControllerRegister() *ControllerRegister {

    cr := &ControllerRegister{

        routers:  make(map[string]*Tree),

        policies: make(map[string]*Tree),

    }

    cr.pool.New = func() interface{} {

        return beecontext.NewContext()

    }

    return cr

}

以上init完成了BeeApp的初始化,同時,初始化了Handler及Server的值(這是兩個很重的參數(shù),后面將會用到),在這里我們可以看到Handler的類型是ControllerRegister,在處理請求時將會用到。

2.routers init

routers init主要是路由的聲明,例如:

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)

我們同樣在初探中提過beego.Get、beego.Router、beego.AutoRouter、beego.Include、beego.AddNamespace等方式聲明的路由最終存儲在BeeApp.Handlers.routers。

二、beego.Run

beego.Run代碼如下:

func Run(params ...string) {

    ...

    BeeApp.Run()

}

beego.Run最終調用了之前已經初始化了的BeeApp,

// Run beego application.

func (app *App) Run() {

    ...

    app.Server.Handler = app.Handlers

    app.Server.ReadTimeout = time.Duration(BConfig.Listen.ServerTimeOut) * time.Second

    app.Server.WriteTimeout = time.Duration(BConfig.Listen.ServerTimeOut) * time.Second

    app.Server.ErrorLog = logs.GetLogger("HTTP")

    // run graceful mode

    if BConfig.Listen.Graceful {

        httpsAddr := BConfig.Listen.HTTPSAddr

        app.Server.Addr = httpsAddr

        if BConfig.Listen.EnableHTTPS {

            go func() {

                ...

                if err := server.ListenAndServeTLS(BConfig.Listen.HTTPSCertFile, BConfig.Listen.HTTPSKeyFile); err != nil {

                    logs.Critical("ListenAndServeTLS: ", err, fmt.Sprintf("%d", os.Getpid()))

                    time.Sleep(100 * time.Microsecond)

                    endRunning <- true

                }

            }()

        }

        if BConfig.Listen.EnableHTTP {

            go func() {

                ...

                if err := server.ListenAndServe(); err != nil {

                    logs.Critical("ListenAndServe: ", err, fmt.Sprintf("%d", os.Getpid()))

                    time.Sleep(100 * time.Microsecond)

                    endRunning <- true

                }

            }()

        }

        <-endRunning

        return

    }

    ...

}

我們知道http.ListenAndServe邏輯如下:

func ListenAndServe(addr string, handler Handler) error {

    server := &Server{Addr: addr, Handler: handler}

    return server.ListenAndServe()

}

app.Server是系統(tǒng)*http.Server,將Handlers傳入app.Server.Handler即是構建了一個http.ListenAndServe中的server,然后在接下來調用server.ListenAndServe。至此,我們可以看到beego的啟動與go中的完全一致。只是在server構建前完成了一系列的routers的存儲以及響應時的匹配

以上是“golang中beego的示例分析”這篇文章的所有內容,感謝各位的閱讀!希望分享的內容對大家有幫助,更多相關知識,歡迎關注億速云行業(yè)資訊頻道!

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經查實,將立刻刪除涉嫌侵權內容。

AI