【问题标题】:Detect cURL timeout in PHP在 PHP 中检测 cURL 超时
【发布时间】:2014-05-12 15:19:44
【问题描述】:

我正在尝试检测 cURL 请求何时超时。如果这有什么不同,我正在使用 curl_multi_exec?

curl_errno() 的输出为 0,这表明它是成功的。然而 curl_error() 的输出是:

操作在 1435 毫秒后超时,其中 -1 个字节中有 0 个 收到了

任何想法为什么错误代码是好的,但错误消息存在?我希望超时的错误代码为 28。

另外,有什么我可以在 curl_getinfo() 中检查超时的吗?

我正在使用 PHP 5.4.4 / cURL 7.24.0。

编辑 1 - 示例代码:

$mh = curl_multi_init();
curl_multi_add_handle($mh,$a);
curl_multi_add_handle($mh,$b);
curl_multi_add_handle($mh,...);

do {
    $mrc = curl_multi_exec($mh, $active);
} while ($mrc == CURLM_CALL_MULTI_PERFORM);

while ($active && $mrc == CURLM_OK) {
    if (curl_multi_select($mh) == -1) usleep(100);
    do { $mrc = curl_multi_exec($mh, $active); }
    while ($mrc == CURLM_CALL_MULTI_PERFORM);
}

【问题讨论】:

  • 你能贴出你的cURL代码吗
  • 当然 - 在上面添加。塔!
  • 不知道为什么会这样。您可以指定超时以尝试使用CURLOPT_CONNECTTIMEOUTCURLOPT_CONNECTTIMEOUT_MS 强制出错。
  • 我在 1 秒内强制执行它。似乎足以收到错误消息。 CURLOPT_CONNECTTIMEOUT_MS 导致相同的行为。

标签: php curl


【解决方案1】:

使用curl_multi_exec() 时,您需要使用curl_multi_info_read() 来获取特定句柄的错误代码。这是由于 PHP 在其简单和多接口中与 cURL 交互的方式,以及错误代码是如何从 cURL 的 curl_multi_info_read() 函数获取到单个句柄上的(参见下面的解释)。

基本上,如果您使用多句柄,调用curl_errno()curl_error() 是不可靠或不准确的。

查看manual中的这个修改示例:

<?php

$urls = array(
   "http://www.cnn.com/",
   "http://www.bbc.co.uk/",
   "http://www.yahoo.com/",
   'http://wijgeiwojgieowjg.com/',
   'http://www.example.com/',
);

$infos = array();

$mh = curl_multi_init();

foreach ($urls as $i => $url) {
    $conn[$i] = curl_init($url);
    curl_setopt($conn[$i], CURLOPT_RETURNTRANSFER, 1);

    if (strpos($url, 'example.com') !== false) {
        // set a really short timeout for one url
        curl_setopt($conn[$i], CURLOPT_TIMEOUT_MS, 10);
    }

    curl_multi_add_handle($mh, $conn[$i]);
}

do {
    $status = curl_multi_exec($mh, $active);

    if (($info = curl_multi_info_read($mh)) !== false) {
        $infos[$info['handle']] = $info;
    }

} while ($status === CURLM_CALL_MULTI_PERFORM || $active);

foreach ($urls as $i => $url) {
    $info = $infos[$conn[$i]];

    echo "$url returned code {$info['result']}";
    if (version_compare(PHP_VERSION, '5.5.0') >= 0) {
        echo ": " . curl_strerror($info['result']);
    }
    echo "\n";

    if ($info['result'] === 0) {
        $res[$i] = curl_multi_getcontent($conn[$i]);
    }

    curl_close($conn[$i]);
}

输出:

http://www.cnn.com/返回代码0

http://www.bbc.co.uk/返回码0

http://www.yahoo.com/返回代码0

http://wijgeiwojgieowjg.com/返回码6

http://www.example.com/返回码28

说明:

具体来说,这是由于 PHP 的 curl_exec() 如何调用 cURL 的 curl_easy_perform,它返回一个 CURLcode(错误代码),并且 PHP 指定了 cURL 选项 CURLOPT_ERRORBUFFER,这会导致缓冲区自动填充错误消息,如果一个发生。

但是当使用 PHP 的 curl_multi_exec() 时,PHP 会调用 cURL 的 curl_multi_perform,它会立即返回并且不会返回多句柄的错误代码。您必须调用 cURL 的 curl_multi_info_read 函数来获取各个句柄的错误代码。

PHP 5.5.0 为 cURL 的 curl_easy_strerror() 提供了一个包装器,它返回一个与 curl 错误代码对应的字符串。

【讨论】:

  • 太棒了,谢谢。正是我需要的。但是,我目前使用curl_getinfo 来检查响应 HTTP 代码。但这不安全吗?我正在尝试检查导致某些请求返回 500 的间歇性网络问题。
  • 使用 curl_getinfo 可以从单个句柄之一获取信息(例如 HTTP 响应代码)。如果单个句柄从 curl_multi_info_read 返回错误条件,则 curl_getinfo 中的部分或全部信息可能不会被填充或相关。
  • 有道理。谢谢!
【解决方案2】:

这对于调试来说真的很令人沮丧,因为 php.net 上的文档和示例与异步 curl 相关的内容非常糟糕。

以下是一些示例代码,可帮助演示 curl_multi_exec 的工作原理:

// Main work loop

do {
    $mrc = curl_multi_exec($mh, $active);
} while ($mrc == CURLM_CALL_MULTI_PERFORM);

while($status = curl_multi_info_read($mh)) {
    if($status['msg'] == CURLMSG_DONE) {

        $errno = $status['result'];
        $errstr = curl_strerror($errno);

        if($errno == CURLE_OK) {

            // This request completed successfully

            // Do something with the info
            $info = curl_getinfo($status['handle');

        } else {

            // There was an error handling this request,
            // like a timeout or something.
            // Note: curl_errno($ch) will probably say success
            // but it's lying to you. Ignore it.

            fwrite(STDERR, "Request failed: Error($errno): $errstr\n");

        }
    }
}

使用上述主工作循环,您可以根据需要多次调用它。类似的东西

while($this->workRemaining()) {
    $this->work();
    usleep(100); // Sleep, or better yet do something productive
}

我不会打印出整个课程。你可以让它为所欲为。

重要的部分是检查$status['result'] 以确定是否有错误。永远不要依赖 curl_getinfo($ch),因为它在 multi_curl 环境中是错误的。

【讨论】:

    猜你喜欢
    • 2012-08-05
    • 1970-01-01
    • 2011-06-27
    • 2012-11-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-29
    • 1970-01-01
    相关资源
    最近更新 更多