0

我在这里听说

一旦您在响应中写入任何内容,请求主体将被关闭,这会阻止您从中读取任何内容

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

4

2 回答 2

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是 a net.Conn,它是与客户端的底层 TCP 连接,bufrw是 a *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()
于 2013-11-06T11:10:35.820 回答
0

从您所指的net/http 文档中

var ErrBodyReadAfterClose = errors.New("http: 关闭正文上的无效读取")

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

但是,我尝试了您提到的博客文章中链接的代码,它在 go 1.1.2 下运行良好,除非我首先写入超过 4k 的数据,在这种情况下r.ParseForm()返回ErrBodyReadAfterClose

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

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

  • 客户端正在发送请求
  • 服务器正在发送响应
  • 服务器缓冲区获得完整的发送响应
  • 服务器块
  • 服务器不再读取客户端请求
  • 客户端缓冲区已满
  • 客户块
  • 僵局
于 2013-11-04T16:47:44.013 回答