Доброе время суток, у меня встала задача сформировать файл в режиме реального времени на загрузку по запросу.
Все работает но беда в том что обработка запроса занимает очень много времени больше 20 минут
Сразу скажу что это API ни каких js тут предлагать не надо.
Во общем суть в том что я пытаюсь клиенту ( в моем случае это обычный браузер ) сказать что обработка займет много времени пытаясь отправить ему код ответа 102 - но код ответа не приходит в запросе.
Я погуглил и мне сказали что нужно добавить 202 как окончательный код ответа "сотки" не входят в этот список поэтому не работает.
Моя логика проста я проверяю http аутентификацию
И пытаюсь сказать заголовками: чувак твой запрос займет много времени не закрывай соединение а просто жди
И типо я твой запрос принял успешно
Далее я пытаюсь отправить заголовки браузеру сразу вызвав ob_flush();
Браузер тупит пару минут но потом закрывает соединение, в дебаге я вижу что он получил код 202 но не где не вижу 102
В итоге обработка не завершена потому что браузер закрыл соединение - как это победить?
header('Cache-Control: no-cache, must-revalidate, max-age=0');
header('HTTP/1.1 102 Processing');
$has_supplied_credentials = !(empty($_SERVER['PHP_AUTH_USER']) && empty($_SERVER['PHP_AUTH_PW']));
$is_not_authenticated = (
!$has_supplied_credentials ||
$_SERVER['PHP_AUTH_USER'] != $AUTH_USER ||
$_SERVER['PHP_AUTH_PW'] != $AUTH_PASS
);
if ($is_not_authenticated) {
header('HTTP/1.1 401 Authorization Required');
header('WWW-Authenticate: Basic realm="Access denied"');
exit;
}
header('HTTP/1.1 102 Processing');
header('HTTP/1.1 202 Accepted');
ob_flush();
set_time_limit(0);
//долгая обработка запроса
sleep(60*30);
$out = fopen('php://output', 'w');
header('HTTP/1.1 200 OK');
header("Content-Type: application/csv");
header("Content-Disposition:attachment;filename=data.csv");
foreach ($text as $string){
fputcsv($out, $string);
}
fclose($out);
UPDATE:
Всем спасибо кто принял участие в этом вопросе, правильный ответ дал
Antonio Solo
PS: Во общем я немного не так изложил проблему, я прекрасно знаю про задачи менеджеры очередей и т.д. который помогают решат подобные проблемы, беда в том что это не подходит для моей задачи, мне нужно для 2 - 3 человек пару раз в сутки в режиме реального времени выгрузить данные и сделать это за
один запрос потмоу что для простых клиентов вроде Power BI или wget нет возможности применять ajax или сложную систему редиректов.
Я решил проблему как и сказал
Antonio Solo я отдавал файл по ходу его обработки, моей ошибкой было что я пытался собрать файл а потом отдать его клиенту. но если отдавать файл кусками то все работает как надо.
перед тем как отдать файл я разумеется сделал
header("Content-Type: application/csv");
header("Content-Disposition:attachment;filename=data.csv");
header('HTTP/1.1 102 Processing');
header('HTTP/1.1 202 Accepted');
ob_end_flush();
set_time_limit(0);
$out = fopen('php://output', 'w');
while(){
// тут тяжолая обработка файла
fputcsv($out, $text[$i]); // в моем случае это csv поэтому я отдаю ее построчно
}
fclose($out); // на этом все
Таким образом, браузер как и любой другой http клиент не разрывает содеинение и ожидает завершения передачи данных, и делается это в 1 запрос.
Я хочу отметить что это решение подходит долеко не для всех задач так как может вызвать большую загрузку сервера ( если например 100 человек разом откроют соединения и т.д. ) - но конкретно в моей задачи это решение устраеват на 100%
Надеюсь моей кометарий поможет людям который столкнулись с такой же задачей.