在 Golang 中没有缓冲 http.ResponseWritter

我正在用 Go 编写一个简单的网络应用程序,我希望我的响应被流式传输到客户端(即,一旦请求被完全处理,就不会缓冲并以块的形式发送):


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


噜噜哒
浏览 275回答 2
2回答

catspeake

正如文档中暗示的那样,有些人ResponseWriter可能会实现该Flusher接口。这意味着您可以执行以下操作:func handle(res http.ResponseWriter, req *http.Request) {&nbsp; fmt.Fprintf(res, "sending first line of data")&nbsp; if f, ok := res.(http.Flusher); ok {&nbsp; &nbsp; &nbsp;f.Flush()&nbsp; } else {&nbsp; &nbsp; &nbsp;log.Println("Damn, no flush");&nbsp; }&nbsp; sleep(10) //not real code&nbsp; fmt.Fprintf(res, "sending second line of data")}请注意缓冲可能发生在网络或客户端的许多其他地方。

梵蒂冈之花

如果我误解了您的问题,但是下面的内容可以解决问题吗?package mainimport (&nbsp; &nbsp; "bytes"&nbsp; &nbsp; "fmt"&nbsp; &nbsp; "net/http")func handler(w http.ResponseWriter, r *http.Request) {&nbsp; &nbsp; body := make([]byte, int(r.ContentLength))&nbsp; &nbsp; b := bytes.NewBuffer(body)&nbsp; &nbsp; if _, err := b.ReadFrom(r.Body); err != nil {&nbsp; &nbsp; &nbsp; &nbsp; fmt.Fprintf(w, "%s", err)&nbsp; &nbsp; }&nbsp; &nbsp; if _, err := b.WriteTo(w); err != nil {&nbsp; &nbsp; &nbsp; &nbsp; fmt.Fprintf(w, "%s", err)&nbsp; &nbsp; }}func main() {&nbsp; &nbsp; http.HandleFunc("/", handler)&nbsp; &nbsp; if err := http.ListenAndServe(":8080", nil); err != nil {&nbsp; &nbsp; &nbsp; &nbsp; panic(err)&nbsp; &nbsp; }}$ curl --data "param1=value1&param2=value2" http://localhost:8080返回:参数1=值1&参数2=值2您可以随时附加任何您想要的数据body,或者在再次将其全部写出之前从其他地方将更多字节读入缓冲区。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go