我试图在 golang 中使用 httptest
包。我发现了一些我不明白的东西。这是 code :
package main
import (
"fmt"
"io/ioutil"
"log"
"net/http"
"net/http/httptest"
)
func main() {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello1"))
}))
ts.Close()
ts = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello2"))
}))
ts.Close()
ts = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(100)
w.Write([]byte("Hello3"))
}))
res, err := http.Get(ts.URL)
if err != nil {
log.Fatal(err)
}
greeting, err := ioutil.ReadAll(res.Body)
res.Body.Close()
if err != nil {
log.Fatal(err)
}
ts.Close()
fmt.Printf("%s", greeting)
}
在此代码示例中,我多次尝试打开和关闭 httptest
服务器。它以某种方式在 The Go Playground 中造成了僵局。我在自己的环境(Go版本:go1.7.4 darwin/amd64)上试了一下,导致挂了,一点 react 都没有。
我的问题是:为什么 w.WriteHeader(100)
导致了死锁,而 w.WriteHeader(200)
却没有?是 Golang 核心库的错误还是我误解了一些用法?谢谢!
最佳答案
如果稍微修改一下代码:
package main
import (
"fmt"
"io/ioutil"
"log"
"net/http"
"net/http/httptest"
)
func main() {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello1"))
}))
ts.Close()
ts = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello2"))
}))
ts.Close()
ts = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(100)
w.Write([]byte("Hello3"))
}))
fmt.Println("before get") ///// . <----
res, err := http.Get(ts.URL)
fmt.Println("after get") ///// . <----
if err != nil {
log.Fatal(err)
}
greeting, err := ioutil.ReadAll(res.Body)
res.Body.Close()
if err != nil {
log.Fatal(err)
}
ts.Close()
fmt.Printf("%s", greeting)
}
然后运行它 - 你只会看到第一行。
这意味着 Go http 客户端需要您提供更多数据。所以就挂线上了
res, err := http.Get(ts.URL)
并且无法到达下面的 ts.Close()
。
下一步 - 让我们修改一个测试,它会关闭一个连接,并以此方式释放一个客户端等待锁:
ts = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(100)
w.Write([]byte("Hello3"))
hj, _ := w.(http.Hijacker)
conn, _, _ := hj.Hijack()
conn.Close()
}))
我明确地关闭了连接,但是这样你就可以同时获得检查字符串和测试完成。试试吧。
当然这是违反 HTTP 协议(protocol)的,所以我得到一个错误:
Get http://127.0.0.1:54243: net/http: HTTP/1.x transport connection broken: unexpected EOF
关于http.ResponseWriter.WriteHeader() 导致死锁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47923284/