如何在Go语言中实现HTTP双工处理程序?

mlnl4t2r  于 2023-03-21  发布在  Go
关注(0)|答案(3)|浏览(152)

我听说
一旦您在响应中写入任何内容,请求正文将被关闭,从而防止您从中阅读任何内容
如果这是真的,我如何编写一个合适的双工处理程序,能够从请求主体读取,进行某种转换,然后以流的方式写入响应主体,就像人们在node.js中所做的那样?

nwsw7zdq

nwsw7zdq1#

我最终设法用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()

connnet.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()
kwvwclae

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缓冲区的大小。

  • 客户端正在发送请求
  • 服务器正在发送响应
  • 服务器缓冲区已满发送响应
  • 服务器块
  • 服务器不再阅读客户端请求
  • 客户端缓冲区填满
  • 客户端块
  • 死锁
rkue9o1l

rkue9o1l3#

一旦您在响应中写入任何内容,请求正文将被关闭,从而防止您从中阅读任何内容
2023年3月:Go 1.22+可能包含该功能,遵循已接受的提议“net/http : add ResponseController.EnableFullDuplex
net/http HTTP/1服务器不允许在开始写入响应后阅读入站请求正文。(请参阅ResponseWriter.Write文档)。
这个限制是因为服务器在写入响应头之前会清空请求主体中所有未读的部分,以避免在阅读响应之前尝试写入完整请求的客户端发生死锁。(请参阅#15527(注解)了解更多上下文。
我建议我们提供一种选择性加入机制来禁用这种行为,允许服务器处理程序在读取请求时写入部分或全部响应。
现在,CL 472636: net/http : support full-duplex HTTP/1 responses开始实现:

// 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()
        }
    }
}

相关问题