我正在用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") }
从客户端的角度来看,这两行将同时发送。任何建议表示赞赏:)
我个人进行的每次写完后都可以刷新,但是在我的用例中,这还不够:
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?
cmd
我在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
如文档中所隐含的,有些ResponseWriter可以实现该Flusher接口。
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") }
请注意,缓冲可能会在网络或客户端的许多其他地方发生。