douningle7944 2014-11-06 00:15
浏览 84

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

I am creating a test Go HTTP server, and I am sending a response header of Transfer-Encoding: chunked so I can continually send new data as I retrieve it. This server should write a chunk to this server every one second. The client should be able to receive them on demand.

Unfortunately, the client(curl in this case), receives all of the chunks at the end of the duration, 5 seconds, rather than receiving one chunk every one second. Also, Go seems to send the Content-Length for me. I want to send the Content-Length at the end, and I want the the header's value to be 0.

Here is the server code:

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条回答 默认 最新

  • dongxiao9583 2015-06-02 18:19
    关注

    The trick appears to be that you simply need to call Flusher.Flush() after each chunk is written. Note also that the "Transfer-Encoding" header will be handled by the writer implicitly, so no need to set it.

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

    You can verify by using 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
    
    ...
    

    You might need to do some research to verify that http.ResponseWriters support concurrent access for use by multiple goroutines.

    Also, see this question for more information about the "X-Content-Type-Options" header.

    评论

报告相同问题?

悬赏问题

  • ¥15 目详情-五一模拟赛详情页
  • ¥15 有了解d3和topogram.js库的吗?有偿请教
  • ¥100 任意维数的K均值聚类
  • ¥15 stamps做sbas-insar,时序沉降图怎么画
  • ¥15 买了个传感器,根据商家发的代码和步骤使用但是代码报错了不会改,有没有人可以看看
  • ¥15 关于#Java#的问题,如何解决?
  • ¥15 加热介质是液体,换热器壳侧导热系数和总的导热系数怎么算
  • ¥100 嵌入式系统基于PIC16F882和热敏电阻的数字温度计
  • ¥15 cmd cl 0x000007b
  • ¥20 BAPI_PR_CHANGE how to add account assignment information for service line