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

时间:2012-08-28 20:54:33

标签: php apache http http-streaming

是否可以将文件上传到apache php服务器而不包含内容长度标题?

我正在尝试将我正在创建的文件作为文件上传流式传输。当我不使用内容长度标题时,我得到了apache“501 Method Not Implemented”。

$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

中读取

1 个答案:

答案 0 :(得分:16)

根据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消息的实体主体。这种编码格式可以应用于请求或响应(duh,它们都是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");