错误的处理"/>
Go学习:错误的处理
不对错误进行处理
package mainimport ("bufio""fmt""learngo/errhandling/fib""os"
)func writeFlie(fileName string) {file, err := os.OpenFile(fileName, os.O_EXCL|os.O_CREATE, 0666)if err != nil {panic(err)}defer file.Close()writer := bufio.NewWriter(file)defer writer.Flush()f := fib.Fib()for i := 0; i < 20; i++ {fmt.Fprintln(writer, f())}
}func main() {/**panic: open fib.txt: The file exists.goroutine 1 [running]:main.writeFlie({0x250faa, 0x7})D:/gospace/learngo/errhandling/defer/defer.go:14 +0x367main.main()D:/gospace/learngo/errhandling/defer/defer.go:28 +0x25*/writeFlie("fib.txt")
}
不对错误进行处理时,程序会直接挂掉并且会打印一些报错信息
错误处理一
package mainimport ("bufio""fmt""learngo/errhandling/fib""os"
)func writeFlie(fileName string) {file, err := os.OpenFile(fileName, os.O_EXCL|os.O_CREATE, 0666)if err != nil {if pathError, ok := err.(*os.PathError); !ok {panic(err)}else {fmt.Printf("%s, %s, %s\n",pathError.Op,pathError.Path,pathError.Err)}}defer file.Close()writer := bufio.NewWriter(file)defer writer.Flush()f := fib.Fib()for i := 0; i < 20; i++ {fmt.Fprintln(writer, f())}
}func main() {// open, fib.txt, The file exists.writeFlie("fib.txt")
}
错误处理二
package filelistingimport ("io/ioutil""net/http""os"
)func HandleFileList(writer http.ResponseWriter, request *http.Request) error {path := request.URL.Path[len("/list/"):]file, err := os.Open(path)if err != nil {return err}defer file.Close()all, err := ioutil.ReadAll(file)if err != nil {return err}writer.Write(all)return nil
}
package mainimport ("learngo/errhandling/filelistingserver/filelisting""log""net/http""os"
)type appHandler func(writer http.ResponseWriter, request *http.Request) errorfunc errWrapper(handler appHandler) func(http.ResponseWriter, *http.Request) {return func(writer http.ResponseWriter, request *http.Request) {err := handler(writer, request)if err != nil {log.Printf("Error occurred "+"handling request: %s",err.Error())code := http.StatusOKswitch {case os.IsNotExist(err):code = http.StatusNotFoundcase os.IsPermission(err):code = http.StatusForbiddendefault:code = http.StatusInternalServerError}http.Error(writer,http.StatusText(code),code)}}
}func main() {http.HandleFunc("/list/",errWrapper(filelisting.HandleFileList))err := http.ListenAndServe(":8888", nil)if err != nil {panic(err)}
}
-
正常访问
-
文件不存在
-
日志
最终版
package mainimport ("learngo/errhandling/filelistingserver/filelisting""log""net/http""os"
)type appHandler func(writer http.ResponseWriter, request *http.Request) errortype userError interface {errorMessage() string
}func errWrapper(handler appHandler) func(http.ResponseWriter, *http.Request) {return func(writer http.ResponseWriter, request *http.Request) {defer func() {if r := recover(); r != nil {log.Printf("Panic: %v", r)http.Error(writer,http.StatusText(http.StatusInternalServerError),http.StatusInternalServerError)}}()err := handler(writer, request)if err != nil {log.Printf("Error occurred "+"handling request: %s", err.Error())// userErrorif userErr, ok := err.(userError); ok {http.Error(writer,userErr.Message(),http.StatusBadRequest)return}// systemErrorcode := http.StatusOKswitch {case os.IsNotExist(err):code = http.StatusNotFoundcase os.IsPermission(err):code = http.StatusForbiddendefault:code = http.StatusInternalServerError}http.Error(writer,http.StatusText(code),code)}}
}func main() {http.HandleFunc("/",errWrapper(filelisting.HandleFileList))err := http.ListenAndServe(":8888", nil)if err != nil {panic(err)}
}
package filelistingimport ("fmt""io/ioutil""net/http""os""strings"
)const prefix = "/list/"type userError stringfunc (e userError) Error() string {return e.Message()
}
func (e userError) Message() string {return string(e)
}func HandleFileList(writer http.ResponseWriter, request *http.Request) error {if strings.Index(request.URL.Path, prefix) != 0 {return userError(fmt.Sprintf("path %s must start with %s",request.URL.Path,prefix))}path := request.URL.Path[len("/list/"):]file, err := os.Open(path)if err != nil {return err}defer file.Close()all, err := ioutil.ReadAll(file)if err != nil {return err}writer.Write(all)return nil
}
-
路由错误
-
文件不存在
-
正常访问
-
日志
总结
recover
- 仅再defer调用中调用
- 获取panic的值
- 如果无法处理,可重新panic
error VS panic
- panic尽量不要用,尽量使用error
- 意料之中的:使用error.如:文件打不开
- 意料之外的:使用panic.如:数组越界
错误处理综合示例
- defer + panic + recpver
- Type Assertion处理error
- 函数式编程调用
更多推荐
Go学习:错误的处理
发布评论