在 Golang 中没有缓冲 http.ResponseWritter [英] Not buffered http.ResponseWritter in Golang
问题描述
我正在用 Go 编写一个简单的 Web 应用程序,我希望我的响应能够流式传输到客户端(即,一旦请求被完全处理,就不会缓冲并以块的形式发送):
I'm writing a simple web app in Go and I want my responses to be streamed to the client (i.e. not buffered and sent in blocks once the request is fully processed) :
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")
}
从客户端的角度来看,两条线路会同时发送.任何建议表示赞赏:)
From the client point of view, the two lines will be sent at the same time. Any suggestions are appreciated :)
可以在我个人进行的每次写入后刷新,但在我的用例中这还不够:
It's possible to flush after each write I personally make, but in my use case it's not enough:
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?
I want the output of my cmd
to be flushed as well. Anyway to "autoflush" the ResponseWritter ?
我在 golang 的邮件列表上找到了帮助.有两种方法可以实现这一点:使用允许接管底层 TCP 的 hijackerHTTP 连接,或在将写入和刷新的 go 例程中管道命令的 stdout 和 stderr :
I found help on golang's mailing list. There is 2 way to achieve this: using hijacker that allow to take over the underlying TCP connection of HTTP, or piping the stdout and stderr of the command in a go routine that will write and flush :
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
接口.
As implied in the documentation, some ResponseWriter
may implement the Flusher
interface.
这意味着你可以这样做:
This means you can do something like this :
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")
}
请注意缓冲可能发生在网络或客户端的许多其他地方.
Be careful that buffering can occur in many other places in the network or client side.
这篇关于在 Golang 中没有缓冲 http.ResponseWritter的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!