add chapter 15.5 (#681)

This commit is contained in:
marjune
2019-07-16 10:56:27 +08:00
committed by ᴊ. ᴄʜᴇɴ
parent c1eb170a8c
commit 0584651404
5 changed files with 158 additions and 4 deletions

View File

@@ -112,5 +112,5 @@ func (obj *Typ) ServeHTTP(w http.ResponseWriter, req *http.Request) {
## 链接
- [目录](directory.md)
- 上一[tcp服务器](15.1.md)
- 上一[tcp服务器](15.1.md)
- 下一节:[访问并读取页面数据](15.3.md)

View File

@@ -150,5 +150,5 @@ go为所有的HTTP状态码定义了常量比如
## 链接
- [目录](directory.md)
- 上一[一个简单的网页服务器](15.2.md)
- 上一[一个简单的网页服务器](15.2.md)
- 下一节:[写一个简单的网页应用](15.4.md)

View File

@@ -62,5 +62,5 @@ func main() {
![](../images/15.4_fig15.1.jpg?raw=true)
- [目录](directory.md)
- 上一[访问并读取页面](15.3.md)
- 下一节:[常见的陷阱与错误](16.0.md)
- 上一[访问并读取页面](15.3.md)
- 下一节:[确保网页应用健壮](15.5.md)

98
eBook/15.5.md Normal file
View File

@@ -0,0 +1,98 @@
# 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)

View File

@@ -0,0 +1,56 @@
// robust_webserver.go
package main
import (
"net/http"
"io"
"log"
)
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)
}
}