panic
1. 停止当前函数执行
2. 一直向上返回,执行每一层的defer
3. 如果没有遇到recover, 程序退出
recover
1. 仅在defer调用中使用
2. 获取panic的值
3. 如果无法处理,可重新panic
示例1
package main import ( "errors" "fmt" ) func tryRecover() { defer func() { r := recover() // r.(type) 判断对象的类型 if err, ok := r.(error); ok { fmt.Println("Error occurred:", err) } else { panic(r) } }() panic(errors.New("this is an error")) } func main() { tryRecover() }
示例2: 处理Web Error
errorHandler.go
package filelisting import ( "net/http" "os" "io/ioutil" "strings" ) const prefix = "/list/" type userError string func (e userError) Error() string { return e.Message() } func (e userError) Message() string { return string(e) } func HandleFileList(writer http.ResponseWriter, request *http.Request) error { index := strings.Index(request.URL.Path, prefix) if index != 0 { return userError("path must start with " + prefix) } path := request.URL.Path[len(prefix):] file, err := os.Open(path) if err != nil { return err } defer file.Close() bytes, err := ioutil.ReadAll(file) if err != nil { return err } writer.Write(bytes) return nil }
web.go
package main import ( "net/http" "imooc/errhanding/filelistingserver/filelisting" "os" "log" ) type appHandler func(writer http.ResponseWriter, request *http.Request) error
// error装饰器 func errWrapper(handler appHandler) func(writer http.ResponseWriter, request *http.Request) { return func(writer http.ResponseWriter, request *http.Request) { defer func() { if r := recover(); r != nil { log.Println("Panic: ", r) http.Error(writer, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) } }() err := handler(writer, request) if err != nil { logger := log.New(os.Stdout, "[Warn]", log.Lshortfile) logger.Printf("Error handling request: %s", err.Error()) // 自定义user error... if userErr, ok := err.(userError); ok { http.Error(writer, userErr.Message(), http.StatusBadRequest) return } code := http.StatusOK switch { case os.IsNotExist(err): code = http.StatusNotFound case os.IsPermission(err): code = http.StatusForbidden default: code = http.StatusInternalServerError } http.Error(writer, http.StatusText(code), code) } } } type userError interface { error Message() string } func main() { http.HandleFunc("/", errWrapper(filelisting.HandleFileList)) err := http.ListenAndServe(":8888", nil) if err != nil { panic(err) } }