Slack PHP API - 避免超时错误

时间:2016-03-24 08:30:20

标签: php curl timeout slack-api slack

我正在尝试使用Slack Custom命令而不太确定如何使用延迟消息,因为Yoda Speak外部API需要3秒以上的时间才能响应。

我做了以下事情:

  • 在我的案例中发送了松弛命令/Yoda并收到reponse_url
  • 将以下post以下内容用于回复网址。
$data_string = '{"response_type": "in_channel", "text":"Checking,please wait..."}' ;
$chs = curl_init();
curl_setopt($chs, CURLOPT_URL, $response_url);
curl_setopt($chs, CURLOPT_POST, true);
curl_setopt($chs, CURLOPT_POSTFIELDS, $data_string); 
curl_setopt($chs, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($chs, CURLOPT_SSL_VERIFYHOST, FALSE);
curl_setopt($chs, CURLOPT_RETURNTRANSFER, true);
curl_setopt($chs, CURLOPT_POST, 1);
curl_setopt($chs, CURLOPT_HTTPHEADER, array('Content-Type:application/json'));
$results = curl_exec($chs);

enter image description here

  • 现在,当我调用Yoda API时,它会出现以下错误"已达到超时"。我读到了delayed responses,但不知道该如何从这里开始。
$chsres = curl_init();
curl_setopt($chsres, CURLOPT_URL, "https://yoda.p.mashape.com/yoda?sentence=welcome+to+stack");
curl_setopt($chsres, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($chsres, CURLOPT_SSL_VERIFYHOST, FALSE);
curl_setopt($chsres, CURLOPT_VERBOSE, true);
curl_setopt($chsres, CURLOPT_TIMEOUT, 45);
curl_setopt($chsres, CURLOPT_RETURNTRANSFER, true);
curl_setopt($chsres, CURLOPT_HTTPHEADER, array('Content-Type:application/json', "X-Mashape-Key:> deMeGoBfMvmshQSemozTqJEY9z0jp1eIhuAjsnx9cQAQsHUifD"));
$resultchsres = curl_exec($chsres);
echo $resultchsres;

有人可以让我知道如何使用延迟回复摆脱超时错误吗?

更新后的代码:

$response_url = $_POST['response_url'];
$text = $_POST['text'];

$term = str_replace(' ', '+', $text);

//https://paypal.slack.com/services/B0VQMHX8W#service_setup
//initial respond with 200OK for timeout
ignore_user_abort(true);
set_time_limit(0);
ob_start();
echo('{"response_type": "in_channel", "text": "Checking, please wait..."}');
header($_SERVER["SERVER_PROTOCOL"] . " 200 OK");
header("Content-Type: application/json");
header('Content-Length: '.ob_get_length());
ob_end_flush();
ob_flush();
flush();


    $chsres = curl_init();
    curl_setopt_array($chsres, array(
        CURLOPT_URL => "https://yoda.p.mashape.com/yoda?sentence=$term",
        CURLOPT_SSL_VERIFYPEER => FALSE,
        CURLOPT_SSL_VERIFYHOST => FALSE,
        CURLOPT_VERBOSE => true,
        CURLOPT_RETURNTRANSFER => FALSE,
        CURLOPT_HTTPHEADER => array('Content-Type:application/json', "X-Mashape-Key: deMeGoBfMvmshQSemozTqJEY9z0jp1eIhuAjsnx9cQAQsHUifD"),
        CURLOPT_RETURNTRANSFER => true
    ));
    $yodaresponse = curl_exec($chsres);

    $curl = curl_init();
    curl_setopt_array($curl, array(
        CURLOPT_URL => $response_url,
        CURLOPT_POST => 1,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_POSTFIELDS => $yodaresponse
    ));

    $resp = curl_exec($curl);
    var_dump($resp);
    curl_close($curl);

我仍然得到相同的错误" Darn - 斜杠命令没有工作(错误消息:Timeout was reached)。通过slash-command"

管理命令

5 个答案:

答案 0 :(得分:6)

您正在做所有正确的事情,只需要更改订单。

  1. 立即响应原始请求并发出200 OK响应。有关详细信息,请参阅this answer,但主要是:

    ignore_user_abort(true);
    ob_start();
    echo('{"response_type": "in_channel", "text": "Checking, please wait..."}');
    header($_SERVER["SERVER_PROTOCOL"] . " 200 OK");
    header("Content-Type: application/json");
    header('Content-Length: '.ob_get_length());
    ob_end_flush();
    ob_flush();
    flush();
    
  2. 然后使用curl制作Yoda API请求,正如您所做的那样

  3. 获得Yoda结果后,请使用curl将其发送至$response_url的Slack,正如您所做的那样。

答案 1 :(得分:2)

如果您正在使用FPM,那么这就是您想要的 - http://php.net/manual/en/function.fastcgi-finish-request.php

您的代码将如下所示......

<?php
$response_url = $_POST["response_url"];
$term = rawurlencode($_POST["text"]);
error_log("POST: " . print_r($_POST, 1));

$response = ["response_type"=>"in_channel", "text"=>"Checking, please wait..."];
echo json_encode($response);
header("Content-Type: application/json");
fastcgi_finish_request();

$ch = curl_init();
...

答案 2 :(得分:1)

从我所看到的in the documentation,您大致正确地做事。只需通过回显任何内容,您就已经传递了200 OK消息,因此无需明确地执行此操作。您应该检查以确保这不是服务器问题;是发布到有效的URL?不会因为重写规则而受到损害吗?

我已经对下面的代码进行了一些更改,包括一些调试将转到您的错误日志(默认情况下是Apache的错误日志)。试一试,至少您将获得更多调试细节。

<?php
$response_url = $_POST["response_url"];
$term = rawurlencode($_POST["text"]);
error_log("POST: " . print_r($_POST, 1));

ob_end_clean();
ob_start();
$response = ["response_type"=>"in_channel", "text"=>"Checking, please wait..."];
echo json_encode($response);
header("Content-Type: application/json");
header("Content-Length: " . ob_get_size());
ob_end_flush();
flush();

$ch = curl_init();
curl_setopt_array($ch, [
    CURLOPT_URL => "https://yoda.p.mashape.com/yoda?sentence=$term",
    CURLOPT_HTTPHEADER => ["X-Mashape-Key: deMeGoBfMvmshQSemozTqJEY9z0jp1eIhuAjsnx9cQAQsHUifD"],
    CURLOPT_RETURNTRANSFER => true
]);
$yodaresponse = curl_exec($ch);
curl_close($ch);
error_log("Yoda response: $yodaresponse");

$yodajson = json_encode([
    "response_type"=>"in_channel",
    "text"=>$yodaresponse
]);
$ch = curl_init();
curl_setopt_array($ch, [
    CURLOPT_URL => $response_url,
    CURLOPT_POST => 1,
    CURLOPT_HTTPHEADER => ["Content-Type: application/json"],
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POSTFIELDS => $yodajson
]);

$resp = curl_exec($ch);
curl_close($ch);
error_log("API response: $resp");

答案 3 :(得分:1)

另一种方法是使用带有短暂超时的curl请求来生成第二个PHP脚本。由于我的提供者对我的PHP环境施加了一些限制(例如没有进程生成),这是唯一对我有用的方法。

第一个脚本将在不久之后终止,并将HTTP OK发送回Slack。第二个脚本将继续运行,处理耗时的处理(例如调用外部API),最后将结果作为延迟响应发送到response_url

第一个脚本

这是您第一个脚本中的curl请求:

<?php>
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, "second.php?redirect_url=$redirect_url");
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
    curl_setopt($ch, CURLOPT_TIMEOUT_MS, 400);     //just some very short timeout        
    curl_setopt($ch, CURLOPT_NOSIGNAL, 1);
    curl_exec($ch);
    curl_close($ch);

    /* send short response back to user, e.g. "Processing your request..." */
?>

超时的长度是任意的,但在我的测试中,一个非常短的超时(例如10ms)不起作用。

您还需要实现一种在两个脚本之间传输输入数据的方法,如图所示,并将request_url作为URL参数传递。

最后,对于斜杠命令,Slack要求您将简短的响应发送回用户。

第二个脚本

这是您的第二个脚本的样子:

<?php
    ignore_user_abort(true);          //very important!
    usleep (500000);                  //to ensure 2nd script responds after 1st
    /* call external API */
    /* send response back to Slack using response_url */
?>

语句ignore_user_abort(true);是强制性的,以确保您的第二个脚本在卷曲超时后继续运行。

{0}的usleep是为了确保第二个脚本在第一个脚本之后响应,但不是强制要求此解决方案起作用。

该示例基于&#34; Continue PHP execution after sending HTTP response&#34;的一个答案。问题

答案 4 :(得分:-1)

发布答案,因为我没有足够的声誉来发表评论......

我遇到了同样的问题,然后我意识到Slack以不同的方式处理请求和响应。具体来说,HTTP请求和响应的第一行不同。

HTTP请求示例:

GET /hello.htm HTTP/1.1
User-Agent: Mozilla/4.0 (compatible; MSIE5.01; Windows NT)
Host: www.tutorialspoint.com
Accept-Language: en-us
Accept-Encoding: gzip, deflate
Connection: Keep-Alive

HTTP响应示例:

HTTP/1.1 200 OK
Date: Mon, 27 Jul 2009 12:28:53 GMT
Server: Apache/2.2.14 (Win32)
Last-Modified: Wed, 22 Jul 2009 19:15:56 GMT
Content-Length: 11
Content-Type: text/xml
Connection: Closed

hello there

如果您可以访问要在PHP中发送的原始字节(从未使用PHP,那么不熟悉),只需使其看起来像响应,而不是请求。否则,立即发送响应,然后执行您需要的工作,并使用新消息发送请求。这可以通过多种方式完成,其中一个由@ miken32概述,我选择在python中调用后台进程。