摘要:
实现一个读取文件内容的服务。
通过defer+panic+recover及type assertion实现错误处理。
handler.go(实现读取):
package filelisting
import (
"io/ioutil"
"net/http"
"os"
"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 {
if strings.Index(request.URL.Path, prefix) != 0 {
return userError("path must start with " + 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
}
web.go(实现服务及错误处理):
import (
"learngo/errhandling/filelistingserver/filelisting"
"log"
"net/http"
"os"
)
type appHandler func(writer http.ResponseWriter, request *http.Request) error
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("%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)
}
}
}
type userError interface {
error
Message() string
}
func main() {
http.HandleFunc("/", errWrapper(filelisting.HandleFileList));
err := http.ListenAndServe(":8888", nil)
if err != nil {
panic(err)
}
}