Golang学习笔记十六

资源管理与错误处理-同一错误处理演示

Posted by CDz on February 15, 2019

这一小节中,重在实战,通过写一个文件服务器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😁