HTTP 协议需要一种方法来确定响应何时结束。根据
RFC2616 第 4 节
4.4 消息长度
消息的传输长度是消息中出现的消息体的长度;也就是说,在应用了任何传输编码之后。当消息中包含消息正文时,该正文的传输长度由以下之一确定(按优先顺序):
1.任何“MUST NOT”包含消息体的响应消息(例如 1xx、204 和 304 响应以及对 HEAD 请求的任何响应)总是由头字段之后的第一个空行终止,无论消息中存在的实体头字段。
2.如果存在 Transfer-Encoding 标头字段(第 14.41 节)并且具有除“identity”以外的任何值,则使用“分块”传输编码(第 3.6 节)定义传输长度,除非消息通过关闭连接终止。
3. 如果存在 Content-Length 头字段(第 14.13 节),则其在 OCTET 中的十进制值表示实体长度和传输长度。如果这两个长度不同(即,如果传输编码
header field is present). If a message is received with both a
Transfer-Encoding header field and a Content-Length header field,
the latter MUST be ignored.
4.如果消息使用媒体类型“multipart/byteranges”,并且没有另外指定传输长度,则该自定界媒体类型定义传输长度。除非发送者知道接收者可以解析它,否则不得使用此媒体类型;来自 1.1 客户端的具有多个字节范围说明符的 Range 标头的存在意味着客户端可以解析 multipart/byteranges 响应。
A range header might be forwarded by a 1.0 proxy that does not
understand multipart/byteranges; in this case the server MUST
delimit the message using methods defined in items 1,3 or 5 of
this section.
5.由服务器关闭连接。(关闭连接不能用于指示请求正文的结束,因为这会使服务器无法发回响应。)
为了与 HTTP/1.0 应用程序兼容,包含消息正文的 HTTP/1.1 请求必须包含有效的 Content-Length 头字段,除非已知服务器符合 HTTP/1.1。如果请求包含消息正文并且没有给出 Content-Length,如果服务器无法确定消息的长度,则应该返回 400(错误请求),如果它希望坚持使用 411(需要长度)接收有效的内容长度。
所有接收实体的 HTTP/1.1 应用程序必须接受“分块”传输编码(第 3.6 节),从而允许在无法提前确定消息长度时将这种机制用于消息。
消息不得同时包含 Content-Length 头字段和非身份传输编码。如果消息确实包含非身份传输编码,则必须忽略 Content-Length。
当在允许消息体的消息中给出 Content-Length 时,其字段值必须与消息体中的八位字节数完全匹配。HTTP/1.1 用户代理必须在收到和检测到无效长度时通知用户。
您不能只是随机添加标题并期望它们被遵守(其他标题可以覆盖)。您首先需要控制所有可能覆盖的标头。
根据这个问题(How to make PHP generate Chunked response),强制“Chunked”的一个好方法是设置 Transfer-Encoding 和 to flush
。也许这两个不是严格需要的。在开始缓冲之前,是否会有任何多余的刷新?