实现一个Web服务器,用户在浏览器中输入文件的路径,然后服务器通过网页把相应文件显示给用户。
web.go:
package mainimport ("net/http""os"".../filelisting""log")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) {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())if userErr, ok := err.(userError); ok {http.Error(writer, userErr.Message(), http.StatusBadRequest)return}code := http.StatusOKswitch {case os.IsNotExist(err): // "文件不存在"错误 404code = http.StatusNotFoundcase os.IsPermission(err): // "没有权限"错误 403code = http.StatusForbiddendefault: // 其他错误(未知错误) 500code = http.StatusInternalServerError}http.Error(writer, http.StatusText(code), code)}}}type userError interface {errorMessage() string}func main() {// 为了避免把程序的内部错误暴露给用户,需要对HandleFileList函数进行包装http.HandleFunc("/list/", errWrapper(filelisting.HandleFileList))err := http.ListenAndServe(":8888", nil)if err != nil {panic(err)}}
handler.go:
package filelisting
import (
"io/ioutil"
"net/http"
"os"
)
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(prefix):]
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
}
用户访问服务器示例:
①成功返回
②文件不存在
用error还是用panic?
尽量不要用panic,尽量用error。
能够预料到的错误都用error;预料不到的错误才用panic。
