PHP Curl Timeout 导致 Javascript 客户端崩溃
Posted
技术标签:
【中文标题】PHP Curl Timeout 导致 Javascript 客户端崩溃【英文标题】:PHP Curl Timeout crashing Javascript client side 【发布时间】:2017-01-06 22:37:02 【问题描述】:我有一个自动同步,它向设备发送 CURL 请求,并且我对我拥有的每台设备(如 60 个)都执行此请求。问题是: - 如果通信成功,一切正常。 - 但如果通信失败,网页将等到超时消失。所以客户端崩溃了 3-4 分钟...我有重要的网格在 3-4 分钟内停止加载数据。
自动同步是 javascript 中的一个函数,它执行 AJAX 请求来调用下面的 php 控制器。我怎样才能防止这种情况?我不知道还能尝试什么... AJAX 是异步的,所以我不明白为什么网页会停止。
控制器:
$list = $panels_repository->getNetwork();
$thread = new PollingThread($list);
$thread->start();
$thread->join();
$result = $thread->result;
$resultLength = sizeof($result);
//...
线程:
class PollingThread extends Thread
private $panels_list;
private $alarm_status;
public $result;
public function __construct($list)
$this->panels_list = $list;
public function run()
$panels_list = $this->panels_list;
$alarmsUpdated = array();
$panels = array();
foreach($panels_list as $panel)
$alarms_list = $panel->getAlarmsList();
//Get updated alarms status
$panel->getDiagnosticStatus($alarms_list);
//Save the results
array_push($alarmsUpdated, $alarms_list);
$this->result = $alarmsUpdated;
获取诊断状态
$input = "<?xml version='1.0' encoding='ISO-8859-1'?>
<?getParameters message?>
<displayMLRequest xmlns='http://www.peek.se/DisplayML/' version='1.12'
dateTime='2008-01-10T15:09:51+02:00'>
<getParameters/>
</displayMLRequest>";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url); //Set IP to communicate
//Set POST XML Input
curl_setopt( $ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: text/xml'));
curl_setopt($ch, CURLOPT_POSTFIELDS, $input);
//Return response as string & TimeOuts
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
//Execute
$output = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
Javascript:
$('#stations_tree').on('changed.jstree', function (e, data)
//....
var dataObject =
type: "Selected",
childrenID: childrenID_array,
parentsID: parentsID_array
;
$.ajax(
type: "POST",
url: "controllers/PanelsController/",
data: dataObject,
cache: false,
success: function ()
$("#dg_selected_stops").jsGrid("loadData");
$("#dg_selected_pids").jsGrid("loadData");
);
).jstree(
plugins: ["checkbox", "state", "types"],
"types":
"default":
"icon" : false
,
core:
data:
url: "json/stations.json",
dataType: "json",
success: function ()
//Save Panels Network as session variable
var dataObject =
type: "Network"
;
$.ajax(
type: "POST",
url: "controllers/PanelsController/",
data: dataObject,
cache: false,
success: function()
//Get EquipmentStatus for each panel
var dataType =
type: "Save"
;
$.ajax(
type: "POST",
url: "controllers/EquipmentStatusController/",
data: dataType,
cache: false,
success: function ()
//Status Unknown
changeTreeIcons();
loadAlarmsData();
polling();
);
);
);
函数 polling() - JS 停止直到超时消失
function polling()
var dataObject =
type: "Polling",
;
$.ajax(
type: 'POST',
url: "controllers/DatabaseController/",
data: dataObject,
success: function(response)
//loadAlarmsData();
//changeTreeIcons();
);
编辑:我已经检查过,如果我在轮询开始后尝试执行 AJAX 请求,网页只会在 php 脚本完成后执行该请求。所以阻塞的 JS 是使用 ajax 请求加载数据的表。我该如何解决这个问题?
【问题讨论】:
这些错误的 CURL 请求是否引发了任何错误? @TheOneandOnlyChemistryBlob 不,如果我在 getDiagnosticStatus 中有回显“测试”,则网络打印 6-7 次。如果我在文件测试中只执行一个 curl 请求,则错误日志是: * 在 DNS 缓存中找到主机名 172.18.56.132 * 正在尝试 172.18.56.132 ... * 连接在 10000 毫秒后超时 * 正在关闭连接 0 如果问题在于网页停止,则发布 javascript,而不是 php 考虑不要在单个页面上发出 60 个请求,而是组合成一个更大的请求/响应。 已编辑后,现在使用 javascript。 @cale_b 问题是我使用了一个包含getDiagnosticStatus 方法的接口。所以每个面板都在实现该接口,因为每个面板都有不同的 IP 进行通信。我怎样才能结合所有?想象一下,第一个面板与成功沟通,但第二个没有。我将如何处理单个较大的请求? 【参考方案1】:这不是复制/粘贴的完整解决方案,但它可以让您了解如何解决您的问题。您可以尝试下一个(仅限 php-fpm)。
在前端使用 js 运行同步并调用您的控制器, 在控制器的客户端发送浏览器响应并在您的 CURL 操作开始之前调用 fastcgi_finish_request()。该函数将所有响应数据刷新到客户端并完成请求,但 PHP 脚本继续工作。
...
$list = $panels_repository->getNetwork();
$key = 'my_unique_operation_key'; // it key need you for get data on client side
$resp = [
'status'=>'start',
'operation_key' => $key
];
echo json_encode($resp);
fastcgi_finish_request(); // close connection and continue ...
$thread = new PollingThread($list, $key); // send $key also
...
在轮询线程中:
...
foreach($panels_list as $panel)
$alarms_list = $panel->getAlarmsList();
//Get updated alarms status
$panel->getDiagnosticStatus($alarms_list);
//Save the results
array_push($alarmsUpdated, $alarms_list);
...
// save operation progress for example in memcache
$progressData = some data about progress and $alarmsUpdated, etc...
$memcache_obj->set('operation_'.$key, json_encode($progressData));
在控制器的某处添加返回数据部分的操作:
function getDataPartially_action()
$key = $_GET['key']; // not forget validate
...
$jsonData = $memcache_obj->get('operation_'.$key); // get current state from memcache by key
echo $jsonData;
exit();
在前端:
// call controller and start operation
$.ajax(
url: '/controller/uri/here',
beforeSend: function()
// here you can place spinner or progress bar ...
,
success: function(json)
// in json you get progress key after fastcgi_finish_request()
// and run visual progress
getDataPartially(key);
);
// load data partially
function getDataPartially(key)
var timerId = setInterval(function()
$.ajax(
url: '/controller/uri/here/getDataPartially_action?key=' + key,
success: function(json)
// in json you have data for grids and progress info
// if json contains finish info stop progress
clearInterval(timerId);
// hide progress bar and etc ...
);, 2000);
附言 在 CURL 函数中,您可以使用 CURLOPT_PROGRESSFUNCTION 并获取有关进度的更多信息:
$ch = curl_init();
curl_setopt ...
curl_setopt($curl, CURLOPT_PROGRESSFUNCTION, 'curl_progress_callback');
...
// where curl_progress_callback is:
function curl_progress_callback($dltotal, $dlnow, $ultotal, $ulnow)
$curlInfo = curl_getinfo($ch); // a lot info about connection
echo $curlInfo['connect_time'];
echo $curlInfo['http_code'] ...
【讨论】:
感谢您的帮助!我正在分析你的答案。你的意思是使用 fastcgi_finish_request() ,所以客户端不要停止。然后用 getDataPartially 读取信息?我的疑问是 url,我应该把 getDataPartially 放在哪里?对不起,伙计,一个小新手:/ @BackSpace,对,您需要使用 getDataPartially 读取信息。为了实现您需要在 Controller 中添加操作并在 getDataPartially() 函数中调用此操作 url。我更新了我的答案。 目前我正在尝试实施您的答案。我用javascript代码更新了我的问题,你能看看吗?我认为问题出在php上,但我不知道。 您的 polling() 函数不是轮询的,它是常规的单个 ajax 请求。轮询工作在循环中,请参阅我的 getDataPartially() 函数。它每 2 秒运行一次,并通过 getDiagnosticStatus 更新数据。在 php 方面,您可以使用 $progressData['status'] = 'finish' 来回答,而在 js 方面,如果响应调用 clearInterval(timerId);它停止轮询请求。更多投票示例:***.com/questions/6835835/… 我在哪里保存了变量 memcache_obj?当调用 getDataPartially 操作时,由于未定义 memcache_obj,php 返回错误以上是关于PHP Curl Timeout 导致 Javascript 客户端崩溃的主要内容,如果未能解决你的问题,请参考以下文章
PHP cURL:CURLOPT_CONNECTTIMEOUT 与 CURLOPT_TIMEOUT