天天看点

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并发编程实战

继续阅读