根据 HTTP 规范,您在技术上不需要指定 Content-Length 标头。从RFC 2616 14.13:
应用程序应该使用这个字段来指示消息体的传输长度,除非这被第 4.4 节中的规则禁止。
Content-Length
但是,对于大多数服务器来说,这是一个非常标准的要求,如果标头丢失或指定不正确,它们通常会发回错误响应。出于所有意图和目的,在这种情况下应该等同于MUST。
问题是(尤其是在保持连接的情况下),服务器不知道您的请求消息何时在没有Content-Length
标头的情况下实际结束。如果您正在流式传输请求实体主体,另一种选择是发送Transfer-Encoding: chunked
标头并一次手动发送一个实体主体块。
因此,总而言之,如果您想在消息中发送实体主体但不想发送Content-Length
标头,那么您唯一真正的选择是发送分块的 HTTP 消息。如果您想流式传输该实体主体并且不提前知道它的长度,这基本上是必需的。
如何对 HTTP 实体主体进行分块编码以进行流式传输...
Transfer-Encoding: chunked
表示您正在根据RFC2616 Sec3.6.1中规定的约束对 HTTP 消息的实体正文进行编码。这种编码格式可以应用于请求或响应(呃,它们都是 HTTP 消息)。这种格式非常有用,因为它允许您在知道实体主体的大小或什至确切地知道该实体主体将是什么之前立即开始发送 HTTP 消息。事实上,这正是 PHP 在echo
没有发送长度标头(如header('Content-Length: 42')
.
我不打算详细介绍分块编码——这就是 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");