实现一个Web服务器,用户在浏览器中输入文件的路径,然后服务器通过网页把相应文件显示给用户。
    web.go:

    1. package main
    2. import (
    3. "net/http"
    4. "os"
    5. ".../filelisting"
    6. "log"
    7. )
    8. type appHandler func(writer http.ResponseWriter, request *http.Request) error
    9. func errWrapper(handler appHandler) func(http.ResponseWriter, *http.Request) {
    10. return func(writer http.ResponseWriter, request *http.Request) {
    11. defer func() {
    12. if r := recover(); r != nil {
    13. log.Printf("Panic: %v", r)
    14. http.Error(writer,
    15. http.StatusText(http.StatusInternalServerError),
    16. http.StatusInternalServerError)
    17. }
    18. }()
    19. err := handler(writer, request)
    20. if err != nil {
    21. log.Printf("Error occurred " + "handling request: %s", err.Error())
    22. if userErr, ok := err.(userError); ok {
    23. http.Error(writer, userErr.Message(), http.StatusBadRequest)
    24. return
    25. }
    26. code := http.StatusOK
    27. switch {
    28. case os.IsNotExist(err): // "文件不存在"错误 404
    29. code = http.StatusNotFound
    30. case os.IsPermission(err): // "没有权限"错误 403
    31. code = http.StatusForbidden
    32. default: // 其他错误(未知错误) 500
    33. code = http.StatusInternalServerError
    34. }
    35. http.Error(writer, http.StatusText(code), code)
    36. }
    37. }
    38. }
    39. type userError interface {
    40. error
    41. Message() string
    42. }
    43. func main() {
    44. // 为了避免把程序的内部错误暴露给用户,需要对HandleFileList函数进行包装
    45. http.HandleFunc("/list/", errWrapper(filelisting.HandleFileList))
    46. err := http.ListenAndServe(":8888", nil)
    47. if err != nil {
    48. panic(err)
    49. }
    50. }

    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
    }
    

    用户访问服务器示例:
    ①成功返回
    image.png
    ②文件不存在
    image.png

    用error还是用panic?
    尽量不要用panic,尽量用error。
    能够预料到的错误都用error;预料不到的错误才用panic。