一尘不染

未在Golang中缓冲http.ResponseWritter

go

我正在用Go编写一个简单的Web应用程序,并且希望将响应流传输到客户端(即,在请求得到完全处理后,不要缓冲并以块的形式发送):

func handle(res http.ResponseWriter, req *http.Request) {
  fmt.Fprintf(res, "sending first line of data")
  sleep(10) //not real code
  fmt.Fprintf(res, "sending second line of data")
}

从客户端的角度来看,这两行将同时发送。任何建议表示赞赏:)

@dystroy答案后编辑

我个人进行的每次写完后都可以刷新,但是在我的用例中,这还不够:

cmd := exec.Command("a long command that outputs lots of lines")
cmd.Stdout = res //where res is a http.ResponseWritter
cmd.Stderr = res
err := cmd.Run()

我也希望cmd刷新我的输出。无论如何“自动刷新” ResponseWritter?

我在golang的邮件列表中找到了帮助。有两种方法可以实现此目的:使用劫持者允许接管HTTP的基础TCP连接,或者在将要写入和刷新的go例程中以管道方式传递命令的stdout和stderr:

pipeReader, pipeWriter := io.Pipe()
cmd.Stdout = pipeWriter
cmd.Stderr = pipeWriter
go writeCmdOutput(res, pipeReader)
err := cmd.Run()
pipeWriter.Close()

//---------------------
func writeCmdOutput(res http.ResponseWriter, pipeReader *io.PipeReader) {
  buffer := make([]byte, BUF_LEN)
  for {
    n, err := pipeReader.Read(buffer)
    if err != nil {
      pipeReader.Close()
      break
    }

    data := buffer[0:n]
    res.Write(data)
    if f, ok := res.(http.Flusher); ok {
      f.Flush()
    }
    //reset buffer
    for i := 0; i < n; i++ {
      buffer[i] = 0
    }
  } 
}

最后更新

更好:http :
//play.golang.org/p/PpbPyXbtEs


阅读 195

收藏
2020-07-02

共1个答案

一尘不染

文档中所隐含,有些ResponseWriter可以实现该Flusher接口。

这意味着您可以执行以下操作:

func handle(res http.ResponseWriter, req *http.Request) {
  fmt.Fprintf(res, "sending first line of data")
  if f, ok := res.(http.Flusher); ok {
     f.Flush()
  } else {
     log.Println("Damn, no flush");
  }
  sleep(10) //not real code
  fmt.Fprintf(res, "sending second line of data")
}

请注意,缓冲可能会在网络或客户端的许多其他地方发生。

2020-07-02