http.ResponseWriter.WriteHeader()导致死锁

我试图在golang中使用 httptest </ code>包。 我发现了我不明白的东西。 这是代码:</ p>

  包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){{n w.WriteHeader(100)
w.Write([] byte(“ Hello3”))
})))

res,err:= http.Get(ts.URL)
if err!= nil {
log.Fatal(err)
}
问候语,错误:= ioutil.ReadAll(res.Body)
res.Body.Close()
如果错误!= nil {
log.Fatal(err)
}

ts.Close()

fmt.Printf(“%s”,问候)
}
</ code> </ pre>

在此 的代码示例,我试图多次打开和关闭 httptest </ code>服务器。 不知何故,它在The Go Playground中造成了僵局。 我在自己的环境(Go版本:go1.7.4 darwin / amd64)上尝试过,它导致挂起,但根本没有响应。</ p>

我的问题是:为什么 w.WriteHeader(100 )</ code>导致死锁,但 w.WriteHeader(200)</ code>不会吗? 是来自Golang核心库的错误还是只是我误解了一些用法? 谢谢!</ p>
</ div>

展开原文

原文

I was trying to use the httptest package in golang. I found out something I don't understand. Here is the 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)
}

In this code example, I was trying to open and close httptest servers several times. Somehow it caused deadlock in The Go Playground. I tried on my own environment (Go version: go1.7.4 darwin/amd64) and it caused hanging without responding at all.

My question is: Why w.WriteHeader(100) caused deadlock but w.WriteHeader(200) doesn't? Is it the bug from the core library of Golang or just I misunderstood some usage? Tks!

dongzhanbi0027
dongzhanbi0027 谢谢!我才明白调用w.WriteHeader(100)之后,它将等待。
2 年多之前 回复
dongshao1021
dongshao1021 我再次阅读了文档,现在我明白了。它只是以这种方式表现。
2 年多之前 回复
doujuchuan9915
doujuchuan9915 谢谢你的榜样!我想知道是否是因为100导致服务器等待来自客户端的以下请求。我只是在玩httptest包!
2 年多之前 回复
douhui1333
douhui1333 它无法解决-请看我的答案。
2 年多之前 回复
duanshan3065
duanshan3065 那没有回答问题。您期望会发生什么?您使用100的原因是什么?只是“看看会发生什么”吗?如果是这样,现在您知道会发生什么。
2 年多之前 回复
douzhulan1815
douzhulan1815 我只是尝试一些httptest代码,发现了这一点。如果认为是错误,我感到困惑。
2 年多之前 回复
duanpie2414
duanpie2414 Close()是否意味着无论如何应该关闭服务器?
2 年多之前 回复
douchen7555
douchen7555 Go似乎没有将100(StatusContinue)响应发送给客户端。如果您重新排序以便首先写Hello3,那么它将最终发送成功的响应(请查看play.golang.org/p/gX1ra-xFSA8-在操场上不起作用,但会在您的系统上起作用),并尝试使用它。是的,顺带一提,您想做什么?
2 年多之前 回复
douxiong5972
douxiong5972 为什么要发送100?您期望发生什么?
2 年多之前 回复
dshu1235
dshu1235 可能100继续答复代码要求进一步的操作,因此库正在等待下一步。
2 年多之前 回复

1个回答

If you slightly modify 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"))
    }))

    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)
}

and run it - you'll see only first line.

That means Go http client want more data from you. So it hangs on line

    res, err := http.Get(ts.URL)

and cannot get to the ts.Close() below.

Next - lets modify a test, so it will close a connection and this way release a clients waiting lock:

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()
}))

I close connection explicitly but this way you get both check strings and test finishes ok. Try it.

Of course it's a HTTP protocol violation so I get an error:

Get http://127.0.0.1:54243: net/http: HTTP/1.x transport connection broken: unexpected EOF
douyan1453
douyan1453 好吧,我想知道我们是否可以称它为一个Go,它永远不会像在RFC(tools.ietf.org/html/rfc7231#section-6.2.1)中那样将持续状态传达给客户端。 可以假设没有太多的应用程序利用此功能?
2 年多之前 回复
Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!
立即提问
相关内容推荐