在本节,最终的代码目录结构如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| dain/ |--context.go |--dain.go |--logger.go |--router.go |--recovery.go |--trie.go |--go.mod static/ |--css/ |--index.css templates/ |--index.tmpl main.go go.mod
|
实现目标
在Web服务器中,因为服务器程序出现 panic 而导致服务端崩溃是无法接受的,所以需要错误恢复机制。
main.go
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| func main() { e := dain.Default()
e.Static("/static", "./static")
e.LoadHTMLGlob("templates/*")
e.Get("/index", func(c *dain.Context) { c.HTML(http.StatusOK, "index.tmpl", c.Path) })
e.Get("/panic", func(c *dain.Context) { array := []int{1, 2, 3} c.JSON(http.StatusOK, dain.H{ "msg": array[100], }) })
e.Run(":9000") }
|
错误恢复
dain/recovery.go
需要预定义一个错误恢复的中间件,用于 recover 错误,以至于 panic 不会导致程序崩溃:
1 2 3 4 5 6 7 8 9 10 11 12
| func Recovery() HandlerFunc { return func(c *Context) { defer func() { if err := recover(); err != nil { message := fmt.Sprintf("%s", err) log.Printf("%s\n\n", trace(message)) c.Fail(http.StatusInternalServerError, "Internal Server Error") } }() c.Next() } }
|
其中,trace 函数用于追踪出错的位置:
1 2 3 4 5 6 7 8 9 10 11 12 13
| func trace(message string) string { var pcs [32]uintptr n := runtime.Callers(3, pcs[:])
var str strings.Builder str.WriteString(message + "\nTraceback:") for _, pc := range pcs[:n] { fn := runtime.FuncForPC(pc) file, line := fn.FileLine(pc) str.WriteString(fmt.Sprintf("\n\t%s:%d", file, line)) } return str.String() }
|