我正在使用 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 宣布的数据后自行关闭?
或者至少可以安全地使用 fopen
和 fread
循环,读取直到我得到 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/