// EnableFullDuplex indicates that the request handler will interleave reads from Request.Body
// with writes to the ResponseWriter.
//
// For HTTP/1 requests, the Go HTTP server by default consumes any unread portion of
// the request body before beginning to write the response, preventing handlers from
// concurrently reading from the request and writing the response.
// Calling EnableFullDuplex disables this behavior and permits handlers to continue to read
// from the request while concurrently writing the response.
//
// For HTTP/2 requests, the Go HTTP server always permits concurrent reads and responses.
func (c *ResponseController) EnableFullDuplex() error {
rw := c.rw
for {
switch t := rw.(type) {
case interface{ EnableFullDuplex() error }:
return t.EnableFullDuplex()
case rwUnwrapper:
rw = t.Unwrap()
default:
return errNotSupported()
}
}
}
3条答案
按热度按时间nwsw7zdq1#
我最终设法用
http.Hijacker
做到了这一点。在发出请求并解析请求头之后,我可以从
*http.Request.Body
读取数据,然后劫持连接并向其写入数据,同时执行如下操作:conn
是net.Conn
,它是到客户端的底层TCP连接,bufrw
是*bufio.ReadWriter
,要编写响应而不关闭主体,我只需我不太确定,但也许有人能回答得更完整,最好偶尔使用以下命令刷新连接中的缓冲区
kwvwclae2#
从您所指的net/http docs
var ErrBodyReadAfterClose =错误。新建(“http:对已关闭主体的读取无效”)
在正文关闭后阅读请求或响应正文时返回ErrBodyReadAfterClose。这通常发生在HTTP处理程序对其ResponseWriter调用WriteHeader或Write后读取正文时
但是我尝试了你提到的博客文章中链接的代码,它在go 1.1.2下工作得很好,除非我先写超过4k的数据,在这种情况下
r.ParseForm()
返回ErrBodyReadAfterClose
。所以我认为答案是否定的,除非响应很短(低于4k),否则一般情况下你不能在go中使用全双工HTTP。
我想说,全双工HTTP请求不太可能有什么大的好处,因为大多数客户端在发送完请求之前不会尝试从响应中读取数据,所以你最多只能赢得客户端和服务器中TCP缓冲区的大小。
rkue9o1l3#
一旦您在响应中写入任何内容,请求正文将被关闭,从而防止您从中阅读任何内容
2023年3月:Go 1.22+可能包含该功能,遵循已接受的提议“
net/http
: addResponseController.EnableFullDuplex
“net/http HTTP/1服务器不允许在开始写入响应后阅读入站请求正文。(请参阅
ResponseWriter.Write
文档)。这个限制是因为服务器在写入响应头之前会清空请求主体中所有未读的部分,以避免在阅读响应之前尝试写入完整请求的客户端发生死锁。(请参阅#15527(注解)了解更多上下文。
我建议我们提供一种选择性加入机制来禁用这种行为,允许服务器处理程序在读取请求时写入部分或全部响应。
现在,CL 472636:
net/http
: support full-duplex HTTP/1 responses开始实现: