这一小节中,重在实战,通过写一个文件服务器webserver的编写,来体现GO语言中同一错误处理方式。其中使用到http包与函数式编程。
filelistserver
先写出webserver错误处理直接panic,后面进行改造
func main() {
//http.HandleFunc("/list/", errWrapper(filelisting.Handerlist))
http.HandleFunc("/list/", func(writer http.ResponseWriter, request *http.Request) {
path := request.URL.Path[len("/list/"):]
file, e := os.Open(path)
if e != nil {
panic(e)
}
defer file.Close()
readAll, e := ioutil.ReadAll(file)
if e != nil {
panic(e)
}
writer.Write(readAll)
})
e := http.ListenAndServe(":8888", nil)//打开一个server监听 8888端口
if e != nil {
panic(e)
}
}
浏览器输入http://localhost:8888/list/fib.txt
1
1
2
3
5
8
13
21
34
55
89
144
233
377
610
987
1597
2584
4181
6765
10946
打印成功,但是这个server是panic错误的,如果出错会直接页面崩溃如当我们输入http://localhost:8888/list/fib.txta
,页面就会该网页无法正常运作
,这样当然很难看。
webserveruo改造第一步
直接将func HandleFunc(pattern string, handler func(ResponseWriter, *Request))
方法的第二个参数,抽取出来到一个文件中。
package filelisting
import (
"io/ioutil"
"net/http"
"os"
)
func Handerlist(writer http.ResponseWriter, request *http.Request) {
path := request.URL.Path[len("/list/"):]
file, e := os.Open(path)
if e != nil {
panic(e)
}
defer file.Close()
readAll, e := ioutil.ReadAll(file)
if e != nil {
panic(e)
}
writer.Write(readAll)
}
func main() {
http.HandleFunc("/list/", filelisting.Handerlist)
e := http.ListenAndServe(":8888", nil)
if e != nil {
panic(e)
}
}
这一步,只是将方法抽取,并没有做其他的事情。
webserveruo改造第二步
定义接口:type appHandler func(writer http.ResponseWriter, request *http.Request) error
,其实就是http.HandleFunc
第二个参数,多加了一个返回值error。
将filelisting.Handerlist
返回error,即实现这个函数接口。
package filelisting
import (
"io/ioutil"
"net/http"
"os"
)
func Handerlist(writer http.ResponseWriter, request *http.Request) error{ //返回error
path := request.URL.Path[len("/list/"):]
file, e := os.Open(path)
if e!=nil {
return e//直接将error返回,上层做出处理
}
defer file.Close()
bytes, e := ioutil.ReadAll(file)
if e != nil {
return e
}
writer.Write(bytes)
return nil
}
定义一个函数处理异常:
func errWrapper( //这个函数的参数是接口appHandler,
//返回函数 func(writer http.ResponseWriter, request *http.Request)
//即http.HandleFunc
//函数体类对错误进行处理
handler appHandler) func(
writer http.ResponseWriter, request *http.Request) {
return func(writer http.ResponseWriter, request *http.Request) {
e := handler(writer, request)
if e != nil {
code := http.StatusOK
switch {
case os.IsNotExist(e):
code = http.StatusNotFound
case os.IsPermission(e):
code=http.StatusForbidden//没有权限
default:
code = http.StatusInternalServerError
}
http.Error(writer,http.StatusText(code),code)
}
}
}
这个异常处理方法,就是处理,我们返回的err,将返回的error信息处理完后,返回一个func(writer http.ResponseWriter, request *http.Request)
函数.
总结
总结错误处理的整体思路:
- 定义接口
type appHandler func(writer http.ResponseWriter, request *http.Request) error
- 实现
appHandler
方法内对错误返回 - 定义方法参数
appHandler
返回函数http.HandleFunc
,方法内处理错误信息
作者所有的学习源码在 go学习源码github地址,如果觉得有用的话帮小智贡献一个star😁