如何在没有Content-Length标头的情况下对HTTP文件上传进行流式传输


How to stream an HTTP file upload without the Content-Length header?

是否可以在不包含内容长度头的情况下将文件上传到apachephp服务器?

我正在尝试将我正在创建的文件作为文件上传进行流式传输。当我不使用内容长度头时,我得到了apache"501方法未实现"。

$sock = fsockopen($host,80,$errno, $error);
fwrite($sock, "POST $resource HTTP/1.1'r'n" .
                     "Host: $host'r'n'r'n");
fwrite($sock,fread($readHandle,filesize($file)));

如果我包括内容长度,它可以正常工作。

服务器正在读取php://input

根据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消息。事实上,当您在不发送header('Content-Length: 42')之类的长度头的情况下echo任何输出时,这正是PHP透明地为您做的。

我不打算详细介绍分块编码——这就是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");