为了账号安全,请及时绑定邮箱和手机立即绑定

在 Golang 中没有缓冲 http.ResponseWritter

在 Golang 中没有缓冲 http.ResponseWritter

Go
噜噜哒 2021-06-30 10:15:26
我正在用 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.ResponseWrittercmd.Stderr = reserr := cmd.Run()我希望我的输出cmd也被刷新。无论如何要“自动刷新” ResponseWritter ?解决方案我在 golang 的邮件列表上找到了帮助。有两种方法可以实现这一点:使用劫持程序来接管 HTTP 的底层 TCP 连接,或者在将写入和刷新的 go 例程中传输命令的 stdout 和 stderr:pipeReader, pipeWriter := io.Pipe()cmd.Stdout = pipeWritercmd.Stderr = pipeWritergo 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
查看完整描述

2 回答

?
catspeake

TA贡献1111条经验 获得超0个赞

正如文档中暗示的那样,有些人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")

}

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


查看完整回答
反对 回复 2021-07-05
?
梵蒂冈之花

TA贡献1900条经验 获得超5个赞

如果我误解了您的问题,但是下面的内容可以解决问题吗?


package main


import (

    "bytes"

    "fmt"

    "net/http"

)


func handler(w http.ResponseWriter, r *http.Request) {

    body := make([]byte, int(r.ContentLength))

    b := bytes.NewBuffer(body)

    if _, err := b.ReadFrom(r.Body); err != nil {

        fmt.Fprintf(w, "%s", err)

    }

    if _, err := b.WriteTo(w); err != nil {

        fmt.Fprintf(w, "%s", err)

    }

}


func main() {

    http.HandleFunc("/", handler)

    if err := http.ListenAndServe(":8080", nil); err != nil {

        panic(err)

    }

}

$ curl --data "param1=value1&param2=value2" http://localhost:8080


返回:


参数1=值1&参数2=值2


您可以随时附加任何您想要的数据body,或者在再次将其全部写出之前从其他地方将更多字节读入缓冲区。


查看完整回答
反对 回复 2021-07-05
  • 2 回答
  • 0 关注
  • 274 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信