Go: 7-2 服务器统一出错处理

如何实现统一的错误处理逻辑 Error部分

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
}

----------------------------------
type appHandler func(writer http.ResponseWriter, request *http.Request) error

func errorWrapper(handlerrr appHandler) func(w http.ResponseWriter, r *http.Request) {
	return func(writer http.ResponseWriter, request *http.Request) {
		err := handlerrr(writer, request)
		if err != nil {
			logs.Warn("Error handling request: %s", err.Error())
			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)
		}

	}
}

func main() {
	http.HandleFunc("/list/", errorWrapper(handler.HandleFileList))
	err := http.ListenAndServe(":8888", nil)
	if err != nil {
		panic(err)
	}
}

panic & recover
recover

func tryRecover() {
	defer func() {
		r := recover()
		if err, ok := r.(error); ok {
			log.Println("Error occured:", err)
		} else {
			panic(r)
		}
	}()

	//panic(errors.New("this is an error"))
	b := 0
	a := 5 / b
	fmt.Println(a)

}

func main() {
	tryRecover()
}

error vs panic
错误处理的综合示例
type appHandler func(writer http.ResponseWriter, request *http.Request) error
type userError interface {
	error
	Message() string
}

func errorWrapper(handlerrr appHandler) func(w http.ResponseWriter, r *http.Request) {
	return func(writer http.ResponseWriter, request *http.Request) {
		defer func() {
			r := recover()
			if r != nil {
				log.Printf("Panic:%v", r)
				http.Error(writer, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
			}
		}()
		err := handlerrr(writer, request)
		if err != nil {
			log.Printf("Error handling request: %s", err.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)
		}

	}
}
---------------------------------------------------------

const prefix = "/list/"

func HandleFileList(writer http.ResponseWriter, request *http.Request) error {
	fmt.Println(request.URL.Path)
	if !strings.HasPrefix(request.URL.Path, prefix) {
		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
}

type userError string

func (e userError) Error() string {
	return e.Message()
}
func (e userError) Message() string {
	return string(e)
}