Некоторые операции занимают слишком много времени, что приводит к аннулированию запроса ajax.
Как мне сначала ответить на запрос, а затем продолжить эту операцию?
Директива 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-скрипте, скрипт будет продолжать работать, даже если пользователь нажал esc или остановился в своем браузере. Как вы это используете?
Одно из них – вернуть контент пользователю и разрешить закрытие соединения при обработке вещей, которые не требуют взаимодействия с пользователем.Следующий пример отправляет пользователю
$response
, закрывая соединение (делаяdo_function_that_takes_five_mins();
spinner /do_function_that_takes_five_mins();
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-скрипт по-прежнему должен соответствовать ограничениям max_execution_time
и memory_limit
что означает, что вы не должны использовать это для манипуляций, занимающих слишком много времени.
Это также будет использовать один процесс Apache – это означает, что вы не должны иметь десятки страниц, которые делают это в одно и то же время.
Тем не менее, хороший трюк, чтобы улучшить опыт использования, я полагаю 😉
Создайте фоновый процесс и верните идентификатор фонового процесса, чтобы пользователь мог проверить его позже через какой-то секретный URL.
Отчасти зависит от того, что вы пытаетесь выполнить.
В моем случае мне нужно было сделать кучу серверной обработки, и только минимальное количество данных было отправлено обратно в браузер – сводная информация действительно.
Я пытался создать отправителя сообщения – отправляет электронное письмо более чем 250 людям, но, возможно, еще много (зависит от количества зарегистрированных в системе).
обработчик почты PHP быстр, но для больших чисел, не достаточно быстрый, поэтому он был вынужден тайм-аут. Чтобы обойти это, мне нужно было отложить тайм-аут на стороне сервера / PHP и держать браузер нависшим, пока все данные не будут суммированы и не отображены.
Мое решение – тизер.
по существу, я дал пользователю сообщение с указанием исходной статистики (попытки отправить это много писем), создал 2 коробки DIV (один для текущей информации о состоянии, второй для окончательной итоговой информации), отобразил нижний колонтитул страницы, начал обработку и когда закончите, обновите итоговую информацию. это выглядит следующим образом:
Начните с сбора данных, которые вы собираетесь обрабатывать, и получите некоторую итоговую информацию. В моем случае я вытащил список адресов электронной почты, подтвердил их и подсчитал.
Затем отобразите «попытку»:
echo "Message contents:"; echo "<blockquote>$msgsubject<p>$msgbody</blockquote><p> </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» и «flush» сверху:
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();
Это будет по существу складывать маленькие изображения 4×20 progress_red рядом друг с другом, заставляя казаться, что красная полоса перемещается по экрану. В моем случае я сделал это 100 раз, исходя из процента того числа, которое я обрабатывал в настоящее время из общего числа для обработки. «Set_time_limit» добавит 3 секунды к существующему лимиту, так что вы знаете, что ваш скрипт не будет работать на стене временного ограничения PHP. Отрегулируйте 3 секунды для вашего приложения по мере необходимости.
даже если страница технически «завершена», код javascript обновит DIV html, и наш индикатор прогресса «переместится».
когда все сделано, я затем сообщаю о том, сколько элементов было фактически обработано, и добавьте это во внешний HTML-файл DIV, и страница завершена:
<script>document.getElementById('content').innerHTML += "Message was sent to $sentcnt people."</script>
Браузер счастлив, потому что у него есть все, что соответствует квалификации (конец страницы синтаксически), пользователь видит, что что-то происходит до самого конца, а сервер
Я, как правило, не использую Javascript, если я могу ему помочь, но в этом случае не было никаких фантазийных вещей CSS, которые делались через Javascript, поэтому довольно просто и легко увидеть, что происходит, и низкие накладные расходы на сайте браузера. И он работает довольно гладко.
Я не утверждаю, что это идеально, но для простого, низкого накладных решений он работает для меня, не создавая cronjobs, дополнительные механизмы очередей или вторичные процессы.
Вам нужен вызов flush()
чтобы немедленно отправить ответ в браузер.