天天看點

beego架構對運作異常的處理

運作時異常

panic

在通常情況下,函數向其調用方報告錯誤的方式都是傳回一個

error

類型的值。但是當遇到緻命錯誤的時候,很可能會使程式無法繼續運作。Go推薦通過調用

panic

函數來報告緻命錯誤,它會停止目前控制流程,并引發一個運作時恐慌。例如:

package main

import "errors"

func main() {
	outerFunc()
}

func outerFunc() {
	innerFunc()
}

func innerFunc() {
	panic(errors.New("an intended fatal error"))
}
           

程式執行後的結果為:

D:\gotest>go run main.go
panic: an intended fatal error

goroutine 1 [running]:
main.innerFunc(...)
        D:/gotest/main.go:14
main.outerFunc(...)
        D:/gotest/main.go:10
main.main()
        D:/gotest/main.go:6 +0x77
exit status 2
           

當調用

innerFunc

函數中的

panic

函數後,

innerFunc

的執行會被停止。緊接着,流程控制權會交給調用方

outerFunc

函數。然後,

outerFunc

函數的執行也會停止。運作時恐慌就沿着調用棧反方向進行傳播,直至到達目前

goroutine

的調用棧的最頂層。一旦達到頂層,就意味着該

goroutine

調用棧中所有函數的執行都已經被停止了,程式已經崩潰。

當然,運作時恐慌并不都是通過調用

panic

函數的方式引發,也可以由Go的運作時系統來引發。例如發生像數組下标越界或類型斷言失敗這樣的運作錯誤時,Go運作時會觸發運作時

panic

recover

為了避免恐慌造成的程式崩潰。Go提供了專用于"攔截"運作時恐慌的内建函數

recover

,它可以使目前的程式從恐慌狀态中恢複并重新獲得流程控制權。

recover

函數被調用後,會傳回一個

interface{}

類型的結果。如果當時的程式正處于運作時恐慌的狀态,那麼這個結果就會是

非nil

的。使用方法:

defer func() {
    if p := recover(); p != nil {
        fmt.Printf("Recovered panic: %s\n", p)
    }
}()
           

beego架構的處理

beego

架構有一些初始化的函數,當你引用

beego

架構時,也就同時執行了初始化函數。(有關包的初始化,可以點選Go init函數詳解進行檢視)。其中

beego\config.go

檔案中的

init

函數涉及到了程式對

panic

的處理。

func init () {
    BConfig = newBconfig()
    // ...
}

func newBConfig() *Config {
    return &Config{
        AppName:                "beego",
        RunMode:                DEV,
        RouterCaseSensitive:    true,
        ServerName:             "beegoServer:" + VERSION,
        RecoverPanic:           true,
        RecoverFunc:            recoverPanic,
        //...
    }
}

func recoverPanic(ctx *context.Context) {
    if err := recover(); err != nil {
        if err == ErrAbort {
            return
        }
        if !BConfig.RecoverPanic {
            panic(err)
        }
        if BConfig.EnableErrorsShow {
            if _,ok := ErrorMaps[fmt.Sprint(err)]; ok {
                exception(fmt.Sprint(err),ctx)
                return
            }
        }
        var stack string
        logs.Critical("the request url is ", ctx.Input.URL())
        logs.Critical(""Handler crashed with error", err)
        for i := 1; ; i++ {
            _, file, line, ok := runtime.Caller(i)
            if !ok {
                break
            }
            logs.Critical(fmt.Sprintf("%s:%d", file, line))
            stack = stack + fmt.Sprintln(fmt.Sprintf("%s:%d", file, line))
        }
        if BConfig.RunMode == DEV || BConfig.EnableErrorsRender {
            showErr(err, ctx, stack)
        }
    }
}
           

從上面的代碼我們可以看到,使用

beego

架構啟動程式時,會初始化一個

recoverPanic

方法。當程式遇到異常時,會進行異常恢複,防止程式崩潰。

beego

runmode

模式為

dev

,且

EnableErrorsRender

(是否将錯誤資訊進行渲染,預設值為

true

,即出錯會提示友好的出錯頁面,對于

API

類型的應用,可能需要将該選項設定為

false

,以防止在

dev

模式下不必要的模闆渲染資訊傳回)為

true

的情況下,會在前端将異常展示出來。而對于其他模式,

beego

隻會在控制台将

panic

出現的調用棧資訊依次列印出來。

參考文章

  1. Go并發程式設計實戰

繼續閱讀