默认的错误处理是 errors.New("错误信息"),这个信息通过 error 类型的返回值进行返回。
推荐:golang教程
举个简单的例子:
func hello(name string) (str string, err error) { if name == "" { err = errors.New("name 不能为空") return } str = fmt.Sprintf("hello: %s", name) return }
当调用这个方法时:
var name = "" str, err := hello(name) if err != nil { fmt.Println(err.Error()) return }
这个默认的错误处理,只是得到了一个错误信息的字符串。
自定义错误处理
咱们定义一个 alarm.go,用于处理告警。
废话不多说,直接看代码。
package alarm import ( "encoding/json" "fmt" "ginDemo/common/function" "path/filepath" "runtime" "strings" ) type errorString struct { s string } type errorInfo struct { Time string `json:"time"` Alarm string `json:"alarm"` Message string `json:"message"` Filename string `json:"filename"` Line int `json:"line"` Funcname string `json:"funcname"` } func (e *errorString) Error() string { return e.s } func New (text string) error { alarm("INFO", text) return &errorString{text} } // 发邮件 func Email (text string) error { alarm("EMAIL", text) return &errorString{text} } // 发短信 func Sms (text string) error { alarm("SMS", text) return &errorString{text} } // 发微信 func WeChat (text string) error { alarm("WX", text) return &errorString{text} } // 告警方法 func alarm(level string, str string) { // 当前时间 currentTime := function.GetTimeStr() // 定义 文件名、行号、方法名 fileName, line, functionName := "?", 0 , "?" pc, fileName, line, ok := runtime.Caller(2) if ok { functionName = runtime.FuncForPC(pc).Name() functionName = filepath.Ext(functionName) functionName = strings.TrimPrefix(functionName, ".") } var msg = errorInfo { Time : currentTime, Alarm : level, Message : str, Filename : fileName, Line : line, Funcname : functionName, } jsons, errs := json.Marshal(msg) if errs != nil { fmt.Println("json marshal error:", errs) } errorJsonInfo := string(jsons) fmt.Println(errorJsonInfo) if level == "EMAIL" { // 执行发邮件 } else if level == "SMS" { // 执行发短信 } else if level == "WX" { // 执行发微信 } else if level == "INFO" { // 执行记日志 } }
看下如何调用:
package v1 import ( "fmt" "ginDemo/common/alarm" "ginDemo/entity" "github.com/gin-gonic/gin" "net/http" ) func AddProduct(c *gin.Context) { // 获取 Get 参数 name := c.Query("name") var res = entity.Result{} str, err := hello(name) if err != nil { res.SetCode(entity.CODE_ERROR) res.SetMessage(err.Error()) c.JSON(http.StatusOK, res) c.Abort() return } res.SetCode(entity.CODE_SUCCESS) res.SetMessage(str) c.JSON(http.StatusOK, res) } func hello(name string) (str string, err error) { if name == "" { err = alarm.WeChat("name 不能为空") return } str = fmt.Sprintf("hello: %s", name) return }
访问:http://localhost:8080/v1/product/add?name=a
{ "code": 1, "msg": "hello: a", "data": null }
未抛出错误,不会输出信息。
访问:http://localhost:8080/v1/product/add
{ "code": -1, "msg": "name 不能为空", "data": null }
抛出了错误,输出信息如下:
{"time":"2019-07-23 22:19:17","alarm":"WX","message":"name 不能为空","filename":"绝对路径/ginDemo/router/v1/product.go","line":33,"funcname":"hello"}
panic 和 recover
当程序不能继续运行的时候,才应该使用 panic 抛出错误。
当程序发生 panic 后,在 defer(延迟函数) 内部可以调用 recover 进行控制,不过有个前提条件,只有在相同的 Go 协程中才可以。
有意抛出的 panic:
package main import ( "fmt" ) func main() { fmt.Println("-- 1 --") defer func() { if r := recover(); r != nil { fmt.Printf("panic: %sn", r) } fmt.Println("-- 2 --") }() panic("i am panic") }
输出:
-- 1 -- panic: i am panic -- 2 --
无意抛出的 panic:
package main import ( "fmt" ) func main() { fmt.Println("-- 1 --") defer func() { if r := recover(); r != nil { fmt.Printf("panic: %sn", r) } fmt.Println("-- 2 --") }() var slice = [] int {1, 2, 3, 4, 5} slice[6] = 6 }
输出:
-- 1 -- panic: runtime error: index out of range -- 2 --