2017-12-21 14 views
1

私は012olの中でhttptestパッケージを使用しようとしていました。私は理解できないことを見つけました。ここでcode次のとおりです。このコード例で http.ResponseWriter.WriteHeader()がデッドロックを引き起こしました

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!

+1

をおそらく '100 Continue'応答コードはそうライブラリ、さらにいくつかのアクションを想定し、次のステップのために待っています。 –

+3

なぜあなたは '100'を送っていますか?何が起こると思いますか? – Flimzy

+1

Goは、100(StatusContinue)応答をクライアントに送信していないようです。あなたがHello3を最初に書くようにそれを並べ替えるならば、それは最終的には成功したレスポンスを送ります(https://play.golang.org/p/gX1ra-xFSA8をチェックしてください - 遊び場では動作しませんが、あなたのシステム)、それを使って遊んでみてください。そして、はい、あなたは何をしたいですか? – Ravi

答えて

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

とそれを実行する - あなたが最初の行のみが表示されます。

これは、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() 
})) 

私は明示的に接続を閉じていますが、チェック文字列とテストの両方を取得し、この方法は、[OK]を終了します。それを試してみてください。もちろん

それは私がエラーを取得してHTTPプロトコル違反です:

Get http://127.0.0.1:54243: net/http: HTTP/1.x transport connection broken: unexpected EOF 
+0

さて、私はバグと呼ぶことができますか?Goは、RFC(https://tools.ietf.org/html/rfc7231#section-6.2.1)のように、Continue Statusをクライアントに伝えることは決してありません。 )。あまりにも多くのアプリケーションがこれを利用するとは思わないでしょうか? – Ravi

関連する問題