Подтвердить что ты не робот

Отправка запросов POST без ожидания ответа?

Я пишу простой сервис REST, который отвечает на запросы клиентов. Все в PHP.

Я забочусь о том, что когда мой сервер отвечает на запрос, это может привести к связыванию ресурсов, если клиентская сторона слишком медленно отправляет ответ "ok".

Как мне отправить запрос POST через lib_curl, чтобы он не дождался каких-либо ответов, а скорее сразу после отправки данных POST?

Возможно ли это? Спасибо!

4b9b3361

Ответ 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(), убедитесь, что ваши сценарии проходят в любом случае.

Ответ 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";