当 web 服务器发生一个恐慌( panic )时,我们的 web 服务器就会终止。这样非常的糟糕:一个 web 服务必须是一个健壮的程序,能够处理可能会出现的问题。

    一个方法是可以在每一个处理函数( handler )中去使用 defer/recover ,但是这样会导致出现很多重复的代码。更加优雅的解决方法是使用 13.5 章节 中的闭包的方法处理错误。我们将这种机制应用到上一节中的 simple webserver 中,当然,它也可以很容易的应用于任何 web 服务器的程序中。

    为了使代码更具可读性,我们为处理函数(HandleFunc)创建一个 type :

    1. type HandleFnc func(http.ResponseWriter,*http.Request)

    我们模仿 13.5 章节 的 errorHandler 函数,创建一个 logPanics 函数:

    1. func logPanics(function HandleFnc) HandleFnc {
    2. return func(writer http.ResponseWriter, request *http.Request) {
    3. defer func() {
    4. if x := recover(); x != nil {
    5. log.Printf("[%v] caught panic: %v", request.RemoteAddr, x)
    6. }
    7. }()
    8. function(writer, request)
    9. }
    10. }

    然后我将处理函数作为回调包装进 logPanics:

    1. http.HandleFunc("/test1", logPanics(SimpleServer))
    2. http.HandleFunc("/test2", logPanics(FormServer))

    处理函数中应该包含一个 panic 的调用,或者像 [1.3 章节] 中的用来检查错误的 check (error) 函数;下面是完整的代码示例:

    译者注:可以在 SimpleServer 中直接写一个 panic (errors.New (“test error”)) 来模拟出现 panic

    Listing 15.11—robust_webserver.go:

    1. package main
    2. import (
    3. "net/http"
    4. "io"
    5. "log"
    6. )
    7. type HandleFnc func(http.ResponseWriter,*http.Request)
    8. // 将上一章节示例 15.10 中的代码复制过来,除了 main() 函数都复制过来
    9. func main() {
    10. http.HandleFunc("/test1", logPanics(SimpleServer))
    11. http.HandleFunc("/test2", logPanics(FormServer))
    12. if err := http.ListenAndServe(":8088", nil); err != nil {
    13. panic(err)
    14. }
    15. }
    16. func logPanics(function HandleFnc) HandleFnc {
    17. return func(writer http.ResponseWriter, request *http.Request) {
    18. defer func() {
    19. if x := recover(); x != nil {
    20. log.Printf("[%v] caught panic: %v", request.RemoteAddr, x)
    21. // 下面一行代码是译者添加,默认出现 panic 只会记录日志,页面就是一个无任何输出的白页面,
    22. // 可以给页面一个错误信息,如下面的示例返回了一个 500
    23. http.Error(writer, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
    24. }
    25. }()
    26. function(writer, request)
    27. }
    28. }