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

Как продолжить процесс после ответа на запрос ajax в PHP?

Некоторые операции занимают слишком много времени, что приводит к тому, что запрос ajax истекает.

Как мне сначала ответить на запрос, а затем продолжить эту операцию?

4b9b3361

Ответ 1

ignore_user_abort и ignore_user_abort, вероятно, то, что вы ищете: оно должно позволить вам отправлять ответ в браузер и после этого выполнять некоторые вычисления на вашем сервере.

Эта статья может заинтересовать вас: Как использовать ignore_user_abort() для обработки вне диапазона; цитирование:
EDIT 2010-03-22: удалил ссылку (указывал на http:// ! waynepan.com/2007/10/11/ ! how-to-use-ignore_user_abort-to-do-process-out-of-band/ - удалил пробелы и !, если вы хотите попробовать), увидев комментарий @Joel.

В принципе, когда вы используете ignore_user_abort(true) в вашем PHP скрипт, script будет продолжен даже если пользователь нажал esc или остановить его браузер. Как ты использовать это?
Одно использование будет вернуть контент пользователю и разрешить соединение должно быть закрыто во время обрабатывать вещи, которые не требуют взаимодействие пользователя.

Следующий пример отправляет $response пользователю, закрыв соединение (создание браузеров spinner/load bar stop), а затем исполняет do_function_that_takes_five_mins();

И приведенный пример:

ignore_user_abort(true);
header("Connection: close");
header("Content-Length: " . mb_strlen($response));
echo $response;
flush();
do_function_that_takes_five_mins();

(Там больше я не копировал-вставлял)


Обратите внимание, что ваш PHP script по-прежнему должен соответствовать ограничениям max_execution_time и memory_limit, что означает, что вы не должны использовать это для манипуляций, которые занимают слишком много.

Это также будет использовать один процесс Apache - это означает, что вы не должны иметь десятки страниц, которые делают это в одно и то же время.

Тем не менее, хороший трюк, чтобы улучшить опыт использования, я полагаю; -)

Ответ 2

Создайте фоновый процесс и верните идентификатор фонового процесса, чтобы пользователь мог проверить его позже через какой-то секретный URL.

Ответ 3

Отчасти зависит от того, что вы пытаетесь выполнить.

В моем случае мне нужно было сделать кучу серверной обработки, и только минимальное количество данных было отправлено обратно в браузер - на самом деле сводная информация.

Я пытался создать отправителя сообщения - отправляет электронное письмо более чем 250 людям, но, возможно, еще много (зависит от количества зарегистрированных в системе).

обработчик почты PHP работает быстро, но для больших чисел, недостаточно быстрый, поэтому он должен был тайм-аут. Чтобы обойти это, мне нужно было отложить тайм-аут на стороне сервера /PHP и держать браузер нависшим, пока все данные не будут суммированы и не отображены.

Мое решение - тизер.

по существу, я дал пользователю сообщение с указанием исходной статистики (попытки отправить это много писем), создал 2 коробки DIV (один для текущей информации о состоянии, второй для окончательной итоговой информации), отобразил нижний колонтитул страницы, запустил обработки, а когда закончите, обновите сводную информацию. это выглядит следующим образом:

Начните с сбора данных, которые вы собираетесь обработать, и получите краткую информацию. В моем случае я вытащил список адресов электронной почты, подтвердил их и подсчитал.

Затем отобразите информацию о "попытке":

echo "Message contents:";
echo "<blockquote>$msgsubject<p>$msgbody</blockquote><p>&nbsp;</p>";
echo "Attempting <strong>" . $num_rows . "</strong> email addresses.";

Теперь создайте несколько DIV для статуса/окончательной информации:

<div id=content name=content>
<div id=progress name=progress style='border: black 1px solid; width: ".$boxwidth."px; height: 20px;'></div>
<br>
</div>

где $boxwidth - это ширина, которую вы хотите, чтобы ваш индикатор выполнения (поясняется ниже)

Обратите внимание, что они по существу пусты - мы их заполним позже.

Наконец, заполните оставшуюся часть страницы, показывая нижний колонтитул страницы (в моем случае я просто "включил" соответствующий файл).

Теперь все, что все еще болтается в буфере страниц, либо на сервере (если PHP буферизуется), либо в браузере (потому что нам еще не сказали, что мы закончили), поэтому позвольте заставить его получить нажатыми и/или отображаемыми с помощью "игнорирования" и "флеша" сверху:

ignore_user_abort(true); 
flush();

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

Итак, периодически повторяя свои данные (я оставлю "как часто" до вас, чтобы выяснить), выведите следующее:

set_time_limit (3);
...
(process your data here)
...
<script>document.getElementById('progress').innerHTML  += "<img src='images/progress_red.gif' width: $width height=20 border=0>"</script>
flush();

Это, по существу, складывает маленькие изображения 4x20 progress_red рядом друг с другом, заставляя казаться, что красная полоса перемещается по экрану. В моем случае я сделал это 100 раз, исходя из процента того числа, которое я обрабатывал в настоящее время из общего числа для обработки. "Set_time_limit" добавит 3 секунды к существующему лимиту, так что вы знаете, что ваш script не будет работать на стене временного ограничения PHP. При необходимости отрегулируйте 3 секунды для вашего приложения.

хотя страница технически "завершена", код javascript обновит HTML-код DIV, и наш индикатор выполнения "переместится".

когда все сделано, я затем сообщаю о том, сколько элементов было фактически обработано, и добавьте это во внешний HTML файл DIV, и страница завершена:

<script>document.getElementById('content').innerHTML  += "Message was sent to $sentcnt people."</script>

Браузер счастлив, потому что у него было все, что было выполнено (конец страницы синтаксически), пользователь видит, что что-то происходит до самого конца, а сервер

Я стараюсь не использовать Javascript, если я могу ему помочь, но в этом случае не было никаких фантазийных вещей CSS, которые делались через Javascript, поэтому довольно просто и легко увидеть, что происходит, и низкие накладные расходы на сайте браузера, И он работает довольно гладко.

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

Ответ 4

Вам нужен вызов flush(), чтобы сразу отправить ответ в браузер.