分块传输编码 - 浏览器行为

29

我正在尝试以分块模式发送数据。所有头信息都已正确设置,并且数据已进行编码。浏览器将我的响应视为分块响应,接受头信息并开始接收数据。

我原本期望浏览器在每接收到一个分块时更新页面,但实际上它会等到所有分块都接收完毕后再显示它们。这是预期的行为吗?

我希望在接收到每个分块后立即看到它的显示效果。当使用curl时,每个分块被接收后都会立即显示。为什么GUI浏览器不会这样做呢?他们是否使用某种缓存机制?

我已经将Cache-Control头部设置为no-cache,所以不确定这是否与缓存有关。


你在使用哪些浏览器?通常浏览器会进行增量渲染,但是它们可能会在内部缓存一段时间,因为重新布局很耗费资源... - Boris Zbarsky
你发送的数据块是什么类型的数据?只是HTML还是包含脚本数据? - qqx
我正在发送 text/html。在 Firefox 和 Chrome 上尝试过,两者都等待接收所有块。 - Dani El
请参阅(更新的)https://dev59.com/8mQn5IYBdhLWcg3wVF7i。 - Frames Catherine White
3个回答

22

据我所知,浏览器需要一些有效载荷来开始渲染接收到的块。
当然,Curl是个例外。

在发送第一个块之前,尝试发送大约1KB的任意数据。

如果你做得正确,浏览器应该会在接收到块时进行渲染。


太棒了!在Firefox、Chrome、Safari甚至Opera中都完美运行!非常感谢你。 - Dani El
1
1KiB确实是一个很好的通用值,更多细节请看这里:https://dev59.com/8mQn5IYBdhLWcg3wVF7i - bodo
1
据我所知,如果浏览器没有收到内容类型头,则只会收集提到的1KB数据。然后他们需要这些数据来猜测他们将要接收什么。此外,防病毒软件也可能会引起此问题,就像我在这里描述的那样:https://dev59.com/uWLVa4cB1Zd3GeqPtBYy#41760573 - Matthias

11

修复您的标题。


截至2019年,如果使用Content-type: text/html,Chrome浏览器将不会发生缓冲。
如果您只想流式传输文本,类似于text/plain,那么仅使用Content-type: text/event-stream也会禁用缓冲。
  1. 如果您使用 Content-type: text/plain,那么 Chrome 仍会缓冲 1 KiB,除非您另外指定 X-Content-Type-Options: nosniff

RFC 2045 指定,如果未指定 Content-Type,则应假定为 Content-type: text/plain; charset=us-ascii

5.2. Content-Type Defaults

Default RFC 822 messages without a MIME Content-Type header are taken by this protocol to be plain text in the US-ASCII character set, which can be explicitly specified as:

Content-type: text/plain; charset=us-ascii

This default is assumed if no Content-Type header field is specified. It is also recommend that this default be assumed when a syntactically invalid Content-Type header field is encountered. In the presence of a MIME-Version header field and the absence of any Content-Type header field, a receiving User Agent can also assume that plain US-ASCII text was the sender's intent. Plain US-ASCII text may still be assumed in the absence of a MIME-Version or the presence of an syntactically invalid Content-Type header field, but the sender's intent might have been otherwise.

浏览器会开始缓冲 text/plain 一段时间,以检查发送的内容是否真的是纯文本或者像图片这样的媒体类型,以防万一省略了 Content-Type,那么它将等同于一个 text/plain 内容类型。这被称为 MIME 类型嗅探。
MIME 类型嗅探 由 Mozilla 定义 如下:

在没有 MIME 类型或者浏览器认为 MIME 类型不正确的情况下,浏览器可能会执行 MIME 嗅探——通过查看资源的字节来猜测正确的 MIME 类型。

每个浏览器的 MIME 嗅探方式和环境都不同。(例如,如果发送的 MIME 类型不合适,Safari 将查看 URL 中的文件扩展名。)一些 MIME 类型代表可执行内容存在安全问题。服务器可以通过发送 X-Content-Type-Options 标头来防止 MIME 嗅探。

根据 Mozilla文档所述:

X-Content-Type-Options响应HTTP头是服务器使用的标记,用于指示在Content-Type头中广告的MIME类型不应更改并应被遵循。这允许退出MIME类型嗅探,或者换句话说,这是一种表明网站管理员知道他们在做什么的方式。

因此添加X-Content-Type-Options:nosniff即可使其正常工作。

2
对我来说,charset=xxxx 是关键。仅使用 Content-type: text/plain(在 Firefox 60.0.9esr 中)输出被缓冲,并且只在接收到所有数据的末尾一次性显示。当更改为 Content-type: text/plain; charset=us-ascii(或 Content-type: text/html; charset=utf8)时,突然间分块渐进式网页呈现按预期工作。 - Matija Nalis
2
@MatijaNalis,应该是 Content-type: text/html; charset=utf-8(或者如果大小写有影响,则为UTF-8)。 - Tesseract

1
浏览器可以在数据传输时处理和呈现数据,无论数据是否以分块方式发送。浏览器呈现响应数据的方式取决于数据结构和所使用的缓冲类型。例如,在浏览器可以呈现图像之前,它需要文档(或足够的文档)、样式表等。
当资源长度在生成资源响应时未知(无法在响应头中包含“Content-Length”)且服务器不想在传输资源后关闭连接时,分块通常很有用。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接