在HTTP中,HTTP ResponseWriter的写入函数缓冲区会不会?

das*_*tan 4 http flush go

假设我们有一个处理HTTP请求的函数,例如:

func handler(w http.ResponseWriter,  r *http.Request) {
    w.Write([]byte("first piece of data"))
    // do something
    w.Write([]byte("second piece of data"))
}  
Run Code Online (Sandbox Code Playgroud)

我想知道如果第一次调用w.Write()被刷新到客户端?

如果它被刷新,那么我们实际上会对客户端做两次响应,这很奇怪,因为我们如何Content-Length在第二次调用写入之前确定?

如果没有刷新(比如数据在本地缓冲),那么如果我们在第一次调用时写入大量数据会怎么样?(堆栈会溢出吗?)

任何解释将不胜感激!:)

thw*_*hwd 6

我想知道如果第一次调用w.Write()被刷新到客户端?

net/http默认情况下,它ResonseWriter有一个(当前为4KB)大输出缓冲区net.Conn.此外,OS通常会缓冲对套接字的写入.因此在大多数情况下会发生某种缓冲.

如果它被刷新,那么我们实际上会对客户端做两次响应,这很奇怪,因为我们怎样才能在第二次写入调用之前确定Content-Length?

那么HTTP 1.1允许持久连接.此类回复通常不包括Content-Length标题.此外,还有HTTP预告片.

如果您的客户端不支持HTTP 1.1和持久连接,那么它们将具有某种读取超时,在此期间您可以根据需要多次写入连接; 这是一个回应.

这与TCP套接字和HTTP实现的本质有关,而不是Go.

如果没有刷新(比如数据在本地缓冲),那么如果我们在第一次调用时写入大量数据会怎么样?(堆栈会溢出吗?)

不,在堆栈上分配缓冲区是没有意义的 - 缓冲区的主体将存在于堆上.如果您达到每进程内存限制,您的应用程序将惊慌失措"内存不足".

也可以看看:

编辑以在评论中回答您的问题:

Chunked Transfer Encoding是HTTP 1.1规范的一部分,在HTTP 1.0中不受支持.

编辑澄清:

只要您编写响应的两个部分所花费的总时间不超过客户端的读取超时,并且您没有指定Content-Length标题,只需编写响应然后关闭连接即可.这完全没问题而不是"hacky".

  • [是的他们这样做](https://golang.org/src/pkg/net/http/transfer.go#L32),从现在开始我将忽略你的评论. (2认同)