从Go服务器发送分块HTTP响应

时间:2014-11-06 00:15:00

标签: go

我正在创建一个测试Go HTTP服务器,我正在发送Transfer-Encoding的响应头:chunked所以我可以在检索它时不断发送新数据。此服务器应每秒向此服务器写一个块。客户应该能够按需接收它们。

不幸的是,客户端(在这种情况下为curl)在持续时间结束时接收所有块,为5秒,而不是每秒接收一个块。此外,Go似乎为我发送了Content-Length。我想在最后发送Content-Length,我希望标题的值为0.

这是服务器代码:

package main

import (
    "fmt"
    "io"
    "log"
    "net/http"
    "time"
)

func main() {
    http.HandleFunc("/test", HandlePost);
    log.Fatal(http.ListenAndServe(":8080", nil))
}

func HandlePost(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Connection", "Keep-Alive")
    w.Header().Set("Transfer-Encoding", "chunked")
    w.Header().Set("X-Content-Type-Options", "nosniff")

    ticker := time.NewTicker(time.Second)
    go func() {
        for t := range ticker.C {
            io.WriteString(w, "Chunk")
            fmt.Println("Tick at", t)
        }
    }()
    time.Sleep(time.Second * 5)
    ticker.Stop()
    fmt.Println("Finished: should return Content-Length: 0 here")
    w.Header().Set("Content-Length", "0")
}

2 个答案:

答案 0 :(得分:22)

诀窍似乎是你需要在每个块写入后调用Flusher.Flush()。另请注意" Transfer-Encoding"标题将由作者隐式处理,因此无需设置它。

func main() {
  http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
    flusher, ok := w.(http.Flusher)
    if !ok {
      panic("expected http.ResponseWriter to be an http.Flusher")
    }
    w.Header().Set("X-Content-Type-Options", "nosniff")
    for i := 1; i <= 10; i++ {
      fmt.Fprintf(w, "Chunk #%d\n", i)
      flusher.Flush() // Trigger "chunked" encoding and send a chunk...
      time.Sleep(500 * time.Millisecond)
    }
  })

  log.Print("Listening on localhost:8080")
  log.Fatal(http.ListenAndServe(":8080", nil))
}

您可以使用telnet验证:

$ telnet localhost 8080
Trying ::1...
Connected to localhost.
Escape character is '^]'.
GET / HTTP/1.1

HTTP/1.1 200 OK
Date: Tue, 02 Jun 2015 18:16:38 GMT
Content-Type: text/plain; charset=utf-8
Transfer-Encoding: chunked

9
Chunk #1

9
Chunk #2

...

您可能需要进行一些研究以验证http.ResponseWriters是否支持多个goroutine使用的并发访问。

另外,请参阅此问题以获取有关"X-Content-Type-Options" header

的更多信息

答案 1 :(得分:0)

看起来httputil提供了NewChunkedReader函数