我在这里听说
一旦您在响应中写入任何内容,请求正文将是 已关闭,这会阻止您阅读其中的任何内容
如果这是真的,我怎样才能编写一个正确的双工处理程序,它能够从请求正文中读取,进行某种转换,然后以流式传输方式写入响应正文,就像人们在 node.js 中所做的那样?
我最终成功地用
http.Hijacker
做到了这一点。
发出请求并解析请求标头后,我可以从
*http.Request.Body
读取内容,然后劫持连接并写入它,同时,如下所示:
hj, ok := w.(http.Hijacker)
if !ok {
http.Error(w, "hijacking not supported", 500)
return
}
conn, bufrw, err := hj.Hijack()
if err != nil {
http.Error(w, err.Error(), 500)
return
}
defer conn.Close()
然后
conn
是一个net.Conn
,它是到客户端的底层TCP连接,bufrw
是一个*bufio.ReadWriter
,并且要在不关闭正文的情况下编写响应,我所要做的就是
_, err = bufrw.WriteString("HTTP/1.1 200 OK\n\n")
_, err = bufrw.WriteString("this")
_, err = bufrw.WriteString("is")
_, err = bufrw.WriteString("the")
_, err = bufrw.WriteString("response")
_, err = bufrw.WriteString("body")
然后我不确定这一点,但也许有人可以完成答案,偶尔用
刷新连接中的缓冲区是个好主意err := bufrw.Flush()
来自您所指的net/http 文档
var ErrBodyReadAfterClose =errors.New("http: 关闭时读取无效 身体”)但是,我尝试了您提到的博客文章中链接的代码,它在 go 1.1.2 下工作正常,除非我首先写入超过 4k 的数据,在这种情况下读取请求或响应时返回ErrBodyReadAfterClose 身体关闭后的身体。这通常发生在 HTTP 处理程序在其上调用 WriteHeader 或 Write 后读取正文 响应作家
r.ParseForm()
返回
ErrBodyReadAfterClose
。所以我认为答案是否定的,一般情况下你不能在 go 中执行全双工 HTTP,除非响应很短(低于 4k)。
我想说,执行全双工 HTTP 请求不太可能带来很大的好处,因为大多数客户端在完成发送请求之前不会尝试读取响应,因此您最多会赢得的是客户端和服务器中的 TCP 缓冲区。 如果超出这些缓冲区,则可能会出现死锁,例如
controller := http.NewResponseController(myHTTPResponseWriter)
controller.EnableFullDuplex()
请参阅 https://pkg.go.dev/net/http#ResponseController.EnableFullDuplex 了解更多信息。