Не в состоянии сделать прогрессивный рендеринг
Несколько лет назад я писал программы CGI на предыдущих работах, которые основывались на прогрессивном рендеринге, поскольку эти программы CGI могли запускаться долго (минуты), создавая строку вывода примерно каждую секунду. Я обнаружил, что сегодня я не могу добиться прогрессивного рендеринга даже с самым простым примером.
Я видел много предложений на эту тему о том, где разместить CSS, скрипты и т. Д. Однако в приведенном ниже тривиальном примере этого нет.
Я не вижу где-нибудь, где браузеры имеют возможность влиять на прогрессивный рендеринг. Я пробовал это на нескольких системах / устройствах с несколькими браузерами (Chrome, Firefox, Opera), все с тем же результатом.
Ниже приведен тривиальный пример, который я ожидаю выводить каждые 2 секунды, но вместо этого он рендерится, когда весь документ завершен. Я что-то упускаю из виду?
#!/usr/bin/env perl
select(STDOUT); $| = 1; # don't buffer stdout
print "Content-Type: text/html\; charset=ISO-8859-1\n\n" ;
print "<html> <head> <title> Testing </title> </head> <body>\n" ;
my $message = "<code>" .
"Why doesn't this render immediately? <br>\n" x 5 .
"</code>\n" ;
for ( my $i=0 ; $i < 5 ; $i++ ) {
print "$message\n" ;
sleep(2) ;
}
print "</body></html>\n" ;
3 ответа
Ваш веб-сервер, вероятно, буферизует ответ. $| = 1;
устанавливает STDOUT
быть автозаполненным каждый раз, когда вы print
устранение последствий буферизации в вашем скрипте, но вам также нужно учитывать буферизацию, которая происходит на вашем веб-сервере.
Там нет команды или последовательности символов для очистки буфера, но вы можете просто отправить достаточное количество данных для заполнения буфера, чтобы он очищался самостоятельно.
Просто отправьте несущественный контент, как кучу пробелов:
print " " x 1024 * 8;
Сколько данных вам нужно отправить, зависит от размера буферов, настроенных для вашего веб-сервера. Типичные размеры буфера составляют 4 КБ или 8 КБ, но имейте в виду, что если ваш сервер сжмет ответ вашего скрипта, вам потребуется распечатать значительно больше (возможно, около 8 МБ пробельных символов), чтобы заполнить буферы сервера, потому что буферы будут заполнены сжатый ответ.
Конечно, вы также можете просто отключить буферизацию на вашем сервере. Как вы это сделаете, зависит от веб-сервера. Для nginx взгляните на X-Accel-Buffering.
Ответ от ccm не работал для меня, но он поставил меня на правильный путь, чтобы найти проблему. Решением было добавить следующее в мою конфигурацию Apache:
SetEnvIfNoCase Request_URI \.cgi$ no-gzip dont-vary
который я нашел из Предотвратить буферизацию вывода с помощью PHP и Apache
Испытывая то, что предложил @ccm, кажется, что размер буфера составляет 1 КБ, что меня устраивает.
Огромное спасибо @ccm за то, что поставили меня на правильный путь!
Вам также нужен ваш веб-сервер, чтобы скрипт CGI работал достаточно долго. Apache по умолчанию имеет время ожидания1 минуту.
Вы уже отключили буферизацию с $_
это нормально. Сценария больше нельзя контролировать. Соединение должно оставаться открытым, даже если вы хотите выполнять частичную передачу, которая в вашем примере на самом деле не нужна.
Это сервер, который отключает его через некоторое время. И как только соединение разорвано, веб-сервер не отправляет оставшуюся часть вашего ответа по проводам, потому что это соединение разорвано и дескриптор CGI отсоединен, поэтому ничто не читает ваш вывод, чтобы передать его.
Вывод: установите для тайм-аута более высокое значение.
Анекдот: Раньше я работал в системе с настройкой тайм-аута около часа, когда приложение бэк-офиса на основе CGI выполняло большие запросы БД по огромной базе данных MySQL, и все это заняло много времени. Люди, которые работали с этим инструментом, обычно начинали его и брали кофе или обедали.