返回

如何在 PHP 中处理分块编码的 HTTP 请求?

php

分块编码:PHP 读取分块编码请求的指南

分块编码是什么?

HTTP 分块编码是一种将大型 HTTP 请求或响应主体分解为一系列较小块的技术。与固定大小的主体相比,这允许更有效地传输数据。每个块由其大小(以 16 进制表示)、一个 CRLF(回车换行)、数据本身,然后是另一个 CRLF 组成。当主体结束时,将发送一个零长度的块。

问题:PHP 无法处理分块编码请求

默认情况下,PHP 无法处理没有 Content-Length 标头的分块编码请求。这可能给处理来自外部服务或设备的 HTTP 请求带来挑战。

解决方案:

有两种主要方法可以解决此问题:

1. 使用 Apache 模块

你可以使用 Apache 模块(如 mod_data)来处理分块编码请求。该模块将解码分块并为 PHP 脚本提供正确的 Content-Length 标头。要启用 mod_data,请在 .htaccess 文件中添加以下行:

LoadModule data_module modules/mod_data.so

2. 使用 PHP fsockopen

PHP fsockopen 函数允许你直接从套接字读取分块编码请求。以下是使用 fsockopen 读取 POST 主体的示例:

$fp = fsockopen('localhost', 80);
$request = "POST /path/to/script HTTP/1.1\r\n" .
    "Transfer-Encoding: chunked\r\n" .
    "Content-Type: application/xml\r\n" .
    "\r\n";
fwrite($fp, $request);
fwrite($fp, "12\r\n<data>Chunk 1</data>\r\n");
fwrite($fp, "10\r\n<data>Chunk 2</data>\r\n");
fwrite($fp, "0\r\n\r\n");
$response = '';
while (!feof($fp)) {
    $response .= fread($fp, 1024);
}
fclose($fp);

示例:读取来自能源监控设备的分块编码数据

以下 PHP 脚本演示了如何使用 fsockopen 从能源监控设备读取分块编码的 XML 数据:

$fp = fsockopen('localhost', 80);
$request = "POST /path/to/script HTTP/1.1\r\n" .
    "Transfer-Encoding: chunked\r\n" .
    "Content-Type: application/xml\r\n" .
    "\r\n";
fwrite($fp, $request);
$data = '';
while (!feof($fp)) {
    $chunk = fread($fp, 1024);
    if (preg_match('/^([0-9a-f]+)\r\n/', $chunk, $matches)) {
        $size = hexdec($matches[1]);
        $data .= fread($fp, $size);
        fread($fp, 2); // Skip CRLF
    }
}
fclose($fp);

// Parse and process the XML data

结论

通过使用 Apache 模块或 PHP fsockopen,你可以轻松地处理分块编码的 HTTP 请求,从而扩展 PHP 的功能并处理来自各种来源的数据。

常见问题解答

1. 什么是分块编码的优点?

分块编码通过消除对 Content-Length 标头的需求,允许更有效地传输大型主体,从而减少延迟和提高吞吐量。

2. 为什么 PHP 默认无法处理分块编码?

PHP 的内置 HTTP 解析器期望在请求中存在 Content-Length 标头,而分块编码请求不提供该标头。

3. 使用 fsockopen 读取分块编码请求有什么好处?

fsockopen 提供了对套接字的直接访问,允许更灵活地处理分块编码请求,无需依赖外部模块。

4. 什么时候应该使用 Apache 模块而不是 fsockopen?

Apache 模块通常是处理分块编码请求的更简单方法,尤其是在处理大量并发请求的情况下。

5. 还有什么其他技术可以处理分块编码?

除了 Apache 模块和 PHP fsockopen 之外,还有一些库和工具可用于处理分块编码,例如 Nginx 分块编码模块和 Node.js chunked-encoding 包。