下面这段代码的主要功能就是建立一个http服务端,通过这个http服务端我们可以在web端查看本地的文件内容。
但是在我们访问的时候如果url输入不正确,就会出现异常,我们通过函数式编程的方式,对http.handleFunc的第二个入参做了封装,让他从一个没有错误返回的函数,变成了一个有错误返回的函数,我们在外面统一进行了错误处理。
下面就是代码以及说明:
package main
import (
"net/http"
"log"
"os"
"io/ioutil"
"strings"
)
const prefix="/list/"
type uesrError string //用来在web端显示错误
func (e uesrError)Error() string{
return e.Message()
}
func (e uesrError)Message() string{
return string(e)
}
func playFileListHandle(w http.ResponseWriter,r *http.Request) error{
if strings.Index(r.URL.Path,prefix)!=0{
return uesrError("path must start"+prefix)
}
path := r.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
}
w.Write(all)
return nil
}
//定义一个函数类型 appHandler 这样就可以将错误返回
type appHandler func(w http.ResponseWriter,r *http.Request) error
//这个函数的入参是一个返回值是error的函数类型,返回值是一个和入参函数有着相同的入参的函数,
// 但是不带返回值,这样做的目的是为了匹配http.HandleFunc,因为http.HandleFunc的第二
// 个参数没有返回值,这样就可以把一个原本没有返回值的函数变成一个有错误返回的函数,这样我们就可以
//在外面对错误进行统一的处理
func errWrapper(handler appHandler) func(w http.ResponseWriter,r *http.Request) {
return func(w http.ResponseWriter,r* http.Request){
defer func(){
r := recover()
log.Printf("panic is %v",r)
http.Error(w,http.StatusText(http.StatusInternalServerError),
http.DefaultMaxHeaderBytes)
return
}()
err := handler(w,r)
if err != nil {
code := http.StatusOK
if userErr,ok := err.(uesrError);ok{
http.Error(w,userErr.Message(),http.StatusBadRequest)
}
switch {
case os.IsNotExist(err):
code = http.StatusNotFound
default:
code = http.StatusInternalServerError
}
http.Error(w,http.StatusText(code),code)
}
}
}
func main() {
http.HandleFunc("/",errWrapper(playFileListHandle))
err :=http.ListenAndServe(":8080",nil)
if err !=nil{
log.Fatal(err.Error())
}
}
看完之后,小伙伴们如果有不懂的地方欢迎提问。
欢迎关注问我团队公众号:
参考内容:慕课网 ccmouse