http.ResponseWriter.WriteHeader()导致死锁

问题描述 投票:1回答:1

我试图在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),它导致挂起而没有响应。

我的问题是:为什么w.WriteHeader(100)导致僵局但w.WriteHeader(200)没有?是来自Golang核心库的错误还是我误解了一些用法? TKS!

http testing go
1个回答
0
投票

如果你稍微修改代码:

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协议违规,所以我收到一个错误:

Get http://127.0.0.1:54243: net/http: HTTP/1.x transport connection broken: unexpected EOF
© www.soinside.com 2019 - 2024. All rights reserved.