如果没有设置超时,为什么cURL连接失败(没有错误)?

时间:2016-03-23 13:38:56

标签: php curl timeout

我有一个PHP脚本通过cURL连接到URL,然后根据返回的HTTP状态代码执行某些操作:

$ch = curl_init();
$options = array(
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_URL            => $url,
            CURLOPT_USERAGENT      => "What?!?"
);
curl_setopt_array($ch, $options);
$out = curl_exec($ch);
$code = curl_getinfo($ch)["http_code"];
curl_close($ch);

if ($code == "200") {
    echo "200";
} else {
   echo "not 200";
}

有些网络服务器的回复速度很慢,而虽然页面在我的浏览器中加载了几秒钟我的脚本,当它尝试连接到该服务器时,告诉我它没有收到积极的(" 200")回复。所以,显然,cURL发起的连接超时了。

但为什么呢?我没有在脚本中设置超时,根据other answers on this site,cURL的默认超时肯定比在浏览器中加载页面所需的三到四秒长。

那么为什么连接会超时,如果显然已经设置为无限,我怎样才能让它更长久?

注意:

  • 相同的网址并不总是超时。所以有时cURL 可以连接。
  • 这不是一个特定的网址,有时会超时,但在不同的时间会有不同的网址。
  • 我在共享服务器上,因此我无权访问任何文件。
  • 我试图查看curl_getinfo($ch)curl_error($ch) - 根据评论中的@ drew010建议 - 但每当问题发生时两者都是空的。
  • 整个脚本运行的时间超过一分钟。在这段时间内,它成功连接到300多个URL。即使其中一个URL失败,也会成功建立其他连接。因此脚本不会超时。
  • cURL也没有超时,因为当我尝试连接到一个脚本睡眠59秒的URL时,cURL成功连接。显然,失败的URL的缓慢本身并不是cURL的问题。

更新

关注@ Karlos'在他的回答中提出建议,我用过:

CURLOPT_VERBOSE        => 1,
CURLOPT_STDERR         => $curl_log

(使用this answer中的代码)并在网址失败时更改了$curl_log中的以下内容(网址和IP已更改):

* About to connect() to www.somesite.com port 80 (#0)
*   Trying 104.16.37.249... * connected
* Connected to www.somesite.com (104.16.37.249) port 80 (#0)
GET /wp_german/?feed=rss2 HTTP/1.1
User-Agent: myURL
Host: www.somesite.com
Accept: */*

* Recv failure: Connection reset by peer
* Closing connection #0

所以,我找到了为什么 - 谢谢@Karlos! - 显然@Axalix是对的,这是一个网络问题。我现在将遵循本网站上针对此类失败提出的建议。感谢大家的帮助!

2 个答案:

答案 0 :(得分:4)

我使用curl的经验告诉我,有时使用选项:

CURLOPT_RETURNTRANSFER => true

服务器可能无法成功回复,或者至少在 curl 必须接收响应并缓存它的时间范围内成功回复,因此结果将由curl返回到你指定的变量。在您的代码中:

$out = curl_exec($ch);

在此stackoverflow问题CURLOPT_RETURNTRANSFER set to true doesnt work on hosting server中,您可以看到选项CURLOPT_RETURNTRANSFER直接受请求的主机Web服务器实现的影响。

当您明确使用响应主体,并且您的代码依赖于响应头时,解决此问题的好方法可能是:

CURLOPT_RETURNTRANSFER => false

并执行curl代码以处理响应标头。

一旦你有了你感兴趣的代码的标题,就可以运行一个回复curl响应的php脚本并自己解析它:

<?php
    $url=isset($_GET['url']) ? $_GET['url'] : 'http://www.example.com';
    $ch= curl_init();
    $options = array(
            CURLOPT_RETURNTRANSFER => false,
            CURLOPT_URL            => $url,
            CURLOPT_USERAGENT      => "myURL"
    );
    curl_setopt_array($ch, $options);
    curl_exec($ch);
    curl_close($ch);
?>

在任何情况下,回复您的问题为什么您的请求都不会出错,我想使用选项 CURLOPT_NOSIGNAL 以及不同的超时选项在set_opt php manual可能会让你更接近它。

为了进一步挖掘,选项 CURLOPT_VERBOSE 可能会帮助您通过STDERR获得有关请求行为的额外信息。

答案 1 :(得分:0)

原因可能是您的托管服务提供商对传出连接施加了一些限制。

以下是保护脚本的方法:

  1. 在DB中创建一个包含所有需要提取的URL的队列。

  2. 每分钟或5分钟运行cron,从数据库中取一些网址 - 将其标记为in progress

  3. 尝试获取这些网址。在DB中将每个提取的网址标记为success

  4. 增加失败计数的失败次数。

  5. 继续通过队列,直到它为空。

  6. 如果您实施此类解决方案,您将能够在任何不利条件下处理每个网址。