如何在 Go 中执行 HTTP 双工处理程序?

问题描述 投票:0回答:3

我在这里听说

一旦您在响应中写入任何内容,请求正文将是 已关闭,这会阻止您阅读其中的任何内容

如果这是真的,我怎样才能编写一个正确的双工处理程序,它能够从请求正文中读取,进行某种转换,然后以流式传输方式写入响应正文,就像人们在 node.js 中所做的那样?

http go http-post duplex
3个回答
1
投票

我最终成功地用

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

0
投票

来自您所指的net/http 文档

var ErrBodyReadAfterClose =errors.New("http: 关闭时读取无效 身体”)

读取请求或响应时返回ErrBodyReadAfterClose 身体关闭后的身体。这通常发生在 HTTP 处理程序在其上调用 WriteHeader 或 Write 后读取正文 响应作家

但是,我尝试了您提到的博客文章中链接的代码,它在 go 1.1.2 下工作正常,除非我首先写入超过 4k 的数据,在这种情况下

r.ParseForm()

 返回 
ErrBodyReadAfterClose

所以我认为答案是否定的,一般情况下你不能在 go 中执行全双工 HTTP,除非响应很短(低于 4k)。

我想说,执行全双工 HTTP 请求不太可能带来很大的好处,因为大多数客户端在完成发送请求之前不会尝试读取响应,因此您最多会赢得的是客户端和服务器中的 TCP 缓冲区。 如果超出这些缓冲区,则可能会出现死锁,例如

    客户端正在发送请求
  • 服务器正在发送响应
  • 服务器缓冲区获得完整的发送响应
  • 服务器块
  • 服务器不再读取客户端请求
  • 客户端缓冲区已满
  • 客户端封锁
  • 僵局

0
投票
因为我遇到了同样的问题,所以就把它扔进去了。我通过在请求处理函数内的编写器上启用双工支持,在没有劫持者的情况下解决了这个问题。例如:

controller := http.NewResponseController(myHTTPResponseWriter) controller.EnableFullDuplex()
请参阅 

https://pkg.go.dev/net/http#ResponseController.EnableFullDuplex 了解更多信息。

© www.soinside.com 2019 - 2024. All rights reserved.