Files
the-way-to-go_ZH_CN/eBook/15.5.md
Haigang Zhou 72f2eccbc5 第十五章修改 (#834)
Co-authored-by: Joe Chen <jc@unknwon.io>
2022-05-17 16:33:20 +08:00

99 lines
3.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 15.5 确保网页应用健壮
当网页应用的处理函数发生 panic服务器会简单地终止运行。这可不妙网页服务器必须是足够健壮的程序能够承受任何可能的突发问题。
首先能想到的是在每个处理函数中使用 `defer`/`recover()`,不过这样会产生太多的重复代码。[13.5 节](13.5.md)使用闭包的错误处理模式是更优雅的方案。我们把这种机制应用到前一章的简单网页服务器上。实际上,它可以被简单地应用到任何网页服务器程序中。
为增强代码可读性,我们为页面处理函数创建一个类型:
```go
type HandleFnc func(http.ResponseWriter, *http.Request)
```
我们的错误处理函数应用了 [13.5 节](13.5.md)的模式,变成了以下的 `logPanics()` 函数:
```go
func logPanics(function HandleFnc) HandleFnc {
return func(writer http.ResponseWriter, request *http.Request) {
defer func() {
if x := recover(); x != nil {
log.Printf("[%v] caught panic: %v", request.RemoteAddr, x)
}
}()
function(writer, request)
}
}
```
然后我们用 `logPanics()` 来包装对处理函数的调用:
```go
http.HandleFunc("/test1", logPanics(SimpleServer))
http.HandleFunc("/test2", logPanics(FormServer))
```
处理函数现在可以恢复 panic 调用,类似 [13.5 节](13.5.md)中的错误检测函数。完整代码如下:
示例 15.11 [robust_webserver.go](examples/chapter_15/robust_webserver.go)
```go
package main
import (
"io"
"log"
"net/http"
)
const form = `<html><body><form action="#" method="post" name="bar">
<input type="text" name="in"/>
<input type="submit" value="Submit"/>
</form></html></body>`
type HandleFnc func(http.ResponseWriter, *http.Request)
/* handle a simple get request */
func SimpleServer(w http.ResponseWriter, request *http.Request) {
io.WriteString(w, "<h1>hello, world</h1>")
}
/* handle a form, both the GET which displays the form
and the POST which processes it.*/
func FormServer(w http.ResponseWriter, request *http.Request) {
w.Header().Set("Content-Type", "text/html")
switch request.Method {
case "GET":
/* display the form to the user */
io.WriteString(w, form)
case "POST":
/* handle the form data, note that ParseForm must
be called before we can extract form data*/
//request.ParseForm();
//io.WriteString(w, request.Form["in"][0])
io.WriteString(w, request.FormValue("in"))
}
}
func main() {
http.HandleFunc("/test1", logPanics(SimpleServer))
http.HandleFunc("/test2", logPanics(FormServer))
if err := http.ListenAndServe(":8088", nil); err != nil {
panic(err)
}
}
func logPanics(function HandleFnc) HandleFnc {
return func(writer http.ResponseWriter, request *http.Request) {
defer func() {
if x := recover(); x != nil {
log.Printf("[%v] caught panic: %v", request.RemoteAddr, x)
}
}()
function(writer, request)
}
}
```
## 链接
- [目录](directory.md)
- 上一节:[写一个简单的网页应用](15.4.md)
- 下一节:[用模板编写网页应用](15.6.md)