根据HTTP规范,你在技术上并不需要指定Content-Length头。来自
RFC 2616 14.13的内容如下:
应用程序应使用此字段指示消息正文的传输长度,除非第4.4节中的规则禁止这样做。
然而,对于大多数服务器来说,这是一个相当标准的要求,如果Content-Length头缺失或指定不正确,它们通常会发送错误响应。在这种情况下,“应该”等同于“必须”。
问题在于(特别是对于保持连接的请求),如果没有Content-Length头,服务器无法知道您的请求消息何时结束。如果您正在流式传输请求实体正文,则另一种选项是发送Transfer-Encoding: chunked头,并手动一次发送一个实体正文块。
总之,如果你想在消息中发送实体主体但不想发送Content-Length
头信息,你唯一的选择就是发送分块的HTTP消息。如果你想流式传输实体主体但又无法提前知道其长度,那么这基本上是必须的。
如何对HTTP实体主体进行分块编码以进行流式传输...
Transfer-Encoding: chunked
意味着你正在根据RFC2616 Sec3.6.1中规定的约束条件对HTTP消息的实体主体进行编码。这种编码格式可以应用于请求或响应(当然了,它们都是HTTP消息)。这种格式非常有用,因为它允许你在不知道实体主体的大小甚至实体主体具体内容的情况下立即开始发送HTTP消息。事实上,这正是PHP在你没有发送像header('Content-Length: 42')
这样的长度头信息时自动透明地为你完成的echo
任何输出的操作。
我不会详细介绍分块编码——这是HTTP规范的内容——但如果您想要流传输请求实体主体,您需要像这样做:
<?php
$sock = fsockopen($host,80,$errno, $error);
$readStream = fopen('/some/file/path.txt', 'r+');
fwrite($sock, "POST /somePath HTTP/1.1\r\n" .
"Host: www.somehost.com\r\n" .
"Transfer-Encoding: chunked\r\n\r\n");
while (!feof($readStream)) {
$chunkData = fread($readStream, $chunkSize);
$chunkLength = strlen($chunkData);
$chunkData = dechex($chunkLength) . "\r\n$chunkData\r\n";
fwrite($sock, $chunkData);
}
fwrite($sock, "0\r\n\r\n");