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

时间:2014-09-25 08:25:27

标签: http go flush

假设我们有一个处理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"))
}  

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

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

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

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

1 个答案:

答案 0 :(得分:6)

  

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

net/http的默认ResonseWriter在其写入的net.Conn上有一个(当前为4KB)大输出缓冲区。此外,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”。​​