php - 防止 PHP HTTP 包装器等待持久连接的关闭

标签 php http http-headers keep-alive

我正在使用 PHP 代码通过 PHP HTTP wrapper 从 HTTP 服务器检索资源,比如:

file_get_contents("http://...");

当 PHP 发送 HTTP/1.0 请求时,服务器响应带有 Connection: Keep-Alive header 的 HTTP/1.1 响应:

HTTP/1.1 200 OK
Connection: Keep-Alive
Content-Length: ...

虽然 PHP 没有办法使用持久连接,但它似乎毫无意义地等待 HTTP 连接关闭。服务器只有在 60 秒不活动后才会关闭它。


有什么方法可以防止 PHP HTTP wrapper 等待服务器关闭连接,而是在收到 Content-Length header 宣布的数据后自行关闭?

或者至少可以安全地使用 fopenfread 循环,读取直到我得到 Content-Length 字节?


我发现的唯一解决方法是设置超时 HTTP context option以减少等待时间。但显然我需要将超时设置得足够高,以确保它不会中断响应的读取,因此它仍然远非理想。


我尝试过但没有成功的其他方法:

  • 使用 HTTP/1.1(使用 protocol_version 上下文选项),希望它能让 PHP 知道持久连接
  • 使用 Connection: close header (服务器忽略它)

最佳答案

$context = stream_context_create(array('http' => array('header'=>"Connection: close\r\n")));
file_get_contents("http://...",false,$context);

你说你已经这样做了,在这种情况下,更好的答案可能是使用 fsockopen 手动写入/读取响应,直到 fgets 返回 false(不要使用 feof,它会挂起,直到连接关闭)。

引用:http://php.net/manual/en/function.fsockopen.php & http://php.net/manual/en/function.fgets.php

编辑: 如前所述,经过进一步测试后,我已经确认这确实也挂起,所以这是一个可以正常工作的修改后的解决方案

<?php
$handle = fsockopen("google.com", 80);
if ($handle) {
    $out = "GET / HTTP/1.1\r\n";
    $out .= "Host: google.com\r\n";
    $out .= "Connection: Keep-Alive\r\n\r\n";
    fwrite($handle, $out);

    $bytesread = 0;
    while (($buffer = fgets($handle, 4096)) !== false) {
        if(strpos($buffer, "Content-Length:") !== false) {
                list(, $len) = explode("Content-Length: ", $buffer);
        }

        if($buffer === "\r\n") {
                break;
        }
    }

    $data = '';
    while($bytesread != intval($len)) {
        $buf = fgets($handle, 1024);
        $bytesread += strlen($buf);
        $data .= $buf;
    }
    fclose($handle);
    print $data;
}
?>

这显然非常简单,缺少很多错误检查,但提供了预期的行为。

关于php - 防止 PHP HTTP 包装器等待持久连接的关闭,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34864179/

相关文章:

php - 执行成功但 num_rows 返回 0 [PHP-MySQL]

php - Amazon Elastic Transcoder - 将持续时间添加到输出返回错误

http - HTTP Content-Length 与实际 body size 不一致怎么办?

javascript - 在不同的表单中使用输入文件元素

python-3.x - 如何在 python3 中通过 http 传输二进制文件?

json - Wget 窗口和多个 --header 开关

android - OkHttp3 java.lang.IllegalArgumentException : Unexpected char 0x2019

PHP MVC,局部 View ?

php - 如何在 CodeIgniter 中为多个 Hook 使用同一个对象?

http - cURL 在收到 404 响应后没有返回