Отправка запросов POST без ожидания ответа?
Я пишу простой сервис REST, который отвечает на запросы клиентов. Все в PHP.
Я забочусь о том, что когда мой сервер отвечает на запрос, это может привести к связыванию ресурсов, если клиентская сторона слишком медленно отправляет ответ "ok".
Как мне отправить запрос POST через lib_curl, чтобы он не дождался каких-либо ответов, а скорее сразу после отправки данных POST?
Возможно ли это? Спасибо!
Ответы
Ответ 1
Вы не можете просто отправлять данные, не получая ответа с помощью HTTP. HTTP всегда отправляет запрос → ответ. Даже если ответ очень короткий (как простой 200 без текста), должен быть ответ. И каждый HTTP-сокет будет ждать ответа.
Если вам не нужен ответ, вы можете добавить процесс на сервер, который делает ваши запросы, и просто нажимаете на него свои данные запроса (например, служба, работающая в фоновом режиме, проверка базы данных запроса, и всегда запускать запрос при добавлении новой записи). Таким образом, вы сделаете запрос асинхронно и можете выйти, как только вы добавите этот запрос в стек.
Также, как сказал meuw, клиент не является частью какого-либо сообщения, которое вы делаете с php. Php - это серверный язык, поэтому, когда клиент запрашивает веб-страницу (файл php), сервер выполняет этот файл (и выполняет все запросы к файлу php), а затем возвращает результат клиенту.
Ответ 2
Здесь:
ob_end_clean();
header("Connection: close\r\n");
header("Content-Encoding: none\r\n");
header("Content-Length: 1");
ignore_user_abort(true);
и завиток:
curl_setopt($curl, CURLOPT_TIMEOUT_MS, 1);
curl_setopt($curl, CURLOPT_NOSIGNAL, 1);
Ответ 3
Если вы действительно не заботитесь об ответе, вам, вероятно, лучше использовать exec
-ing команду wget. Об этом упоминается в некоторых других ответах, но здесь очень простая функция для отправки пакета _POST
с помощью этого подхода (который является асинхронным и занимает 1-2 мс):
function wget_request($url, $post_array, $check_ssl=true) {
$cmd = "curl -X POST -H 'Content-Type: application/json'";
$cmd.= " -d '" . json_encode($post_array) . "' '" . $url . "'";
if (!$check_ssl){
$cmd.= "' --insecure"; // this can speed things up, though it not secure
}
$cmd .= " > /dev/null 2>&1 &"; //just dismiss the response
exec($cmd, $output, $exit);
return $exit == 0;
}
Кредиты: функция была адаптирована сhttps://segment.com/blog/how-to-make-async-requests-in-php/
Ответ 4
http://curl.haxx.se/mail/lib-2002-05/0090.html
libcurl не имеет асинхронного интерфейса. Вы можете сделать это сами или используя потоки или используя неблокирующий "мультиинтерфейс", который Предложения libcurl. Читайте на мульти интерфейс здесь:
http://curl.haxx.se/libcurl/c/libcurl-multi.html
Пример PHP для нескольких интерфейсов:
http://www.phpied.com/simultaneuos-http-requests-in-php-with-curl/
Ответ 5
Я никогда не пробовал этого, но установка CURLOPT_TIMEOUT
на очень низкое значение могла бы сделать трюк. Попробуйте 0
или 0.1
.
Однако я не знаю, как cURL и клиент будут вести себя с этим, будет ли активное соединение отменено, когда соединение уже установлено, и тайм-аут будет достигнут. Тебе придется попробовать. Если вы вызываете PHP-скрипты, возможно ignore_user_abort()
, убедитесь, что ваши сценарии проходят в любом случае.
Ответ 6
Как говорят другие люди, когда вы делаете http-запрос, вам нужно ждать ответа.
В PHP вы можете сделать запрос с помощью функции exec.
Проверьте эту ссылку: команда php exec (или аналогичная), чтобы не дождаться результата
Ответ 7
Если у вас есть 2 сервера PHP, взаимодействующих друг с другом, например, сервер 1 хочет отправить данные JSON на сервер 2, сервер 2 выполняет тяжелую работу и завершает соединение сразу после получения данных, поэтому серверу 1 не нужно ждать результата. Вы можете сделать это так:
Сервер 1 (клиент создает запрос POST с данными JSON):
Используйте CURL, не используйте file_get_contents(), потому что, по моему опыту, file_get_contents() не обрабатывает Connection: правильно закрывает заголовок HTTP и не прерывает соединение должным образом.
$curl = curl_init('http://server2.com/');
curl_setopt($curl, CURLOPT_HEADER, false);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_HTTPHEADER, ["Content-type: application/json"]);
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode(['some data']));
$response = curl_exec($curl);
$status = curl_getinfo($curl, CURLINFO_HTTP_CODE);
if ($status !== 200) {
exit("Failed with status {$status}, response {$response}, curl_error " . curl_error($curl) . ", curl_errno " . curl_errno($curl));
}
curl_close($curl);
echo $response;
Сервер 2:
Используется измененный код из bubba-h57.
// Cause we are clever and don't want the rest of the script to be bound by a timeout.
// Set to zero so no time limit is imposed from here on out.
set_time_limit(0);
// Client disconnect should NOT abort our script execution
ignore_user_abort(true);
// Clean (erase) the output buffer and turn off output buffering
// in case there was anything up in there to begin with.
ob_end_clean();
// Turn on output buffering, because ... we just turned it off ...
// if it was on.
ob_start();
echo 'I received the data, closing connection now, bye.';
// Return the length of the output buffer
$size = ob_get_length();
// Send headers to tell the browser to close the connection
// Remember, the headers must be called prior to any actual
// input being sent via our flush(es) below.
header("Connection: close");
// Hack how to turn off mod deflate in Apache (gzip compression).
header("Content-Encoding: none");
header("Content-Length: {$size}");
// Set the HTTP response code
http_response_code(200);
// Flush (send) the output buffer and turn off output buffering
ob_end_flush();
// Flush (send) the output buffer
// This looks like overkill, but trust me. I know, you really don't need this
// unless you do need it, in which case, you will be glad you had it!
@ob_flush();
// Flush system output buffer
// I know, more over kill looking stuff, but this
// Flushes the system write buffers of PHP and whatever backend PHP is using
// (CGI, a web server, etc). This attempts to push current output all the way
// to the browser with a few caveats.
flush();
// Close current session.
session_write_close();
// Here, you can proceed with some heavy work.
echo "This won't be sent, the connection should be already closed";