【发布时间】:2013-11-04 15:31:50
【问题描述】:
我听说here那个
在响应中写入任何内容后,请求正文将是 关闭它会阻止您从中读取任何内容
如果这是真的,我如何编写一个适当的双工处理程序,它能够从请求正文中读取,进行某种转换,然后以流式方式写入响应正文,就像人们在节点中所做的那样.js ?
【问题讨论】:
我听说here那个
在响应中写入任何内容后,请求正文将是 关闭它会阻止您从中读取任何内容
如果这是真的,我如何编写一个适当的双工处理程序,它能够从请求正文中读取,进行某种转换,然后以流式方式写入响应正文,就像人们在节点中所做的那样.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 docs
var ErrBodyReadAfterClose = errors.New("http: 关闭时读取无效 身体")
读取请求或响应时返回 ErrBodyReadAfterClose 身体关闭后的身体。这通常发生在 在 HTTP 处理程序调用 WriteHeader 或 Write 后读取正文 响应者
但是我尝试了您提到的博客文章中链接的代码,它在 go 1.1.2 下运行良好,除非我先写入超过 4k 的数据,在这种情况下 r.ParseForm() 返回 ErrBodyReadAfterClose。
所以我认为答案是否定的,除非响应很短(低于 4k),否则通常不能在 go 中执行全双工 HTTP。
我想说的是,执行全双工 HTTP 请求不太可能带来很大的好处,因为大多数客户端在完成发送请求之前不会尝试从响应中读取,所以你会赢得最多的是大小客户端和服务器中的 TCP 缓冲区。如果超出这些缓冲区,可能会出现死锁,例如
【讨论】: