- Notifications
You must be signed in to change notification settings - Fork18.4k
Description
What version of Go are you using (go version)?
$ go version
go version go1.10.1 linux/amd64
Does this issue reproduce with the latest release?
yes
What operating system and processor architecture are you using (go env)?
GOARCH="amd64"
GOBIN=""
GOCACHE="/home/test/.cache/go-build"
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
GORACE=""
GOROOT="/home/test/go"
GOTMPDIR=""
GOTOOLDIR="/home/test/go/pkg/tool/linux_amd64"
GCCGO="gccgo"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build614182611=/tmp/go-build -gno-record-gcc-switches"
and nginx version: nginx/1.13.3
What did you do?
Here is my client:
package mainimport ( "fmt" "net/http" "sync" "time" "errors" "bytes" "io/ioutil")type Client struct { urlBase string httpClient *http.Client}func NewClient(url string) *Client { cc := &Client{ urlBase: url, httpClient: &http.Client{Transport: &http.Transport{MaxIdleConnsPerHost: 100, MaxIdleConns: 100, IdleConnTimeout: 90 * time.Second, ExpectContinueTimeout: 5 * time.Second}}, } cc.httpClient.Timeout = 5 * time.Second return cc}func (self *Client) Send(content []byte) error { if content == nil { return errors.New("nil content") } body := &bytes.Buffer{} body.Write(content) begin := time.Now() req, err := http.NewRequest("POST", self.urlBase, body) if err != nil { return fmt.Errorf("Send %+v (from %v to %v)", err, begin, time.Now()) } req.Header = make(http.Header) req.Header.Set("Content-Type", "application/json") begin = time.Now() resp, err := self.httpClient.Do(req) if err != nil { return fmt.Errorf("Send %+v (from %v to %v)", err, begin, time.Now()) } defer resp.Body.Close() if resp.StatusCode >= http.StatusBadRequest { bs, _ := ioutil.ReadAll(resp.Body) return fmt.Errorf("Send : HTTP : %d , BODY : %s , REQ : %s", resp.StatusCode, string(bs), string(content)) } bs, err := ioutil.ReadAll(resp.Body) if err != nil { return fmt.Errorf("Send : ERR : %v", err) } fmt.Println("Send : Resp : ", string(bs)) return nil}func main() { client := NewClient( "https://test.cn", // I use /etc/hosts to bind the domain ) var content = []byte(`{"test":1}`) var wg sync.WaitGroup for i := 0; i < 100; i++ { wg.Add(1) go func() { defer wg.Done() client.Send(content) }() } wg.Wait()}And here is my nginx configure of http2:
http2_max_concurrent_streams 40960; http2_max_requests 3; http2_max_field_size 8k; http2_max_header_size 32k; http2_recv_buffer_size 1024k; http2_recv_timeout 120s;What did you expect to see?
I expect all requests are successfully.
What did you see instead?
But I got 400 occasionally and foundclient prematurely closed stream: only 0 out of 10 bytes of request body received line in nginx log.
I usedGODEBUG to try to figure out, and found data not sent afterEND_HEADERS:
2018/04/23 18:32:25 http2: Transport encoding header ":method" = "POST"2018/04/23 18:32:25 http2: Transport encoding header ":path" = "/"2018/04/23 18:32:25 http2: Transport encoding header ":scheme" = "https"2018/04/23 18:32:25 http2: Transport encoding header "content-type" = "application/json"2018/04/23 18:32:25 http2: Transport encoding header "content-length" = "10"2018/04/23 18:32:25 http2: Transport encoding header "accept-encoding" = "gzip"2018/04/23 18:32:25 http2: Transport encoding header "user-agent" = "Go-http-client/2.0"2018/04/23 18:32:25 http2: Framer 0xc4205480e0: wrote HEADERS flags=END_HEADERS stream=5 len=82018/04/23 18:32:25 http2: Framer 0xc4205480e0: wrote DATA flags=END_STREAM stream=5 len=0 data=""That's the reason why nginx responsed400 directly.