Я пытаюсь использовать команду Slack Custom и не очень уверен, как использовать отложенные сообщения, поскольку Yoda Speak External API занимает больше 3 секунд, чтобы ответить.
Я сделал следующее:
/Yoda
в моем случае и получил reponse_url
. post
URL-адрес ответа, выполните следующие действия. $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);
$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-команде"
Вы делаете все правильно, просто нужно изменить порядок.
Ответьте на исходный запрос с ответом 200 OK
немедленно. Подробнее см. В этом ответе , но по существу:
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();
Затем сделайте запрос API Yoda, используя curl, как вы делаете
$response_url
используя curl, как вы это делаете. Из того, что я вижу в документации , вы делаете вещи в основном правильно. Просто повторив что-нибудь, вы уже передаете сообщение 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");
Если вы используете 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(); ...
Отправка ответа, поскольку у меня недостаточно репутации для публикации комментариев …
У меня была та же проблема, и я понял, что 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.
Другим подходом, который будет работать, является использование запроса на завивание с коротким таймаутом для создания второго скрипта 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, 250); //just some very short timeout curl_exec($ch); curl_close($ch); /* send short response back to user, eg "Processing your request..." */ ?>
Длительность тайм-аутов произвольная, однако в моих тестах очень короткий тайм-аут (например, 10 мс) не работал.
Вам также потребуется реализовать способ передачи входных данных между двумя сценариями, как показано на примере передачи параметра request_url
качестве параметра URL.
Наконец, для команд slash 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,5 сек – это обеспечение того, чтобы второй скрипт отвечал после первого, но не обязательно для этого решения.
Пример основан на одном ответе на вопрос « Продолжить выполнение PHP после отправки ответа HTTP ».