Заголовок «Transfer-Encoding: chunked» в PHP. Для чего нужна прокладка?

Как было предложено в ответе на предыдущий вопрос (Внешний Oauth PHP: как отображать ожидающее сообщение во время ожидания обратного вызова (без использования AJAX) ), я использую кодировку передачи: chunked для отображения ожидающего сообщения во время выполнения некоторых задач. Мои первые попытки не увенчались успехом, и я нашел решение в этом вопросе "Transfer-Encoding: chunked" заголовок в PHP. Существует «заполнение» из 1024 пробелов. Без этой прокладки не работает. Я гуглил, но не могу найти, для чего это дополнение. Вот пример кода (из соответствующего вопроса).

<?php
        header('Content-Encoding', 'chunked');
        header('Transfer-Encoding', 'chunked');
        header('Content-Type', 'text/html');
        header('Connection', 'keep-alive');

        ob_flush();
        flush();

        $p = "";  //padding
        for ($i=0; $i < 1024; $i++) { 
            $p .= " ";
        };
        echo $p;

        ob_flush();
        flush();

        for ($i = 0; $i < 10000; $i++) {
            echo "string";
            ob_flush();
            flush();
            sleep(2);
        }

?>

Есть ли у кого-нибудь объяснение, почему он работает с «заполнением» и не работает без него?


person Jean-Marc Dormoy    schedule 26.11.2012    source источник
comment
Что именно происходит без заполнения?   -  person deceze♦    schedule 26.11.2012
comment
извините, я отсутствовал некоторое время. Без заполнения страница остается пустой до тех пор, пока скрипт не будет завершен, а затем весь контент будет обслуживаться (я не пробовал с 10 000 итераций, а только с 10 :))   -  person Jean-Marc Dormoy    schedule 26.11.2012


Ответы (2)



Я понятия не имею, что должен делать этот отступ, и на самом деле он не должен работать (кто-то может просветить меня, если я ошибаюсь). Идея кодирования по частям заключается в том, что вы отправляете свои данные кусками. Каждый фрагмент состоит из строки, содержащей длину фрагмента, за которой следует новая строка, а затем данные фрагмента. Ответ может содержать столько фрагментов, сколько вы хотите. Таким образом, в основном ответ из 3 фрагментов, содержащих «Привет», будет выглядеть так:

5 <--- this is the length of the chunk, that is "Hello" == 5 chars
Hello  <--- This is a the actual data
<-- an empty line is between the chunks
5
Hello

5
Hello

<-- send two empty lines to end the transmission

Поэтому я бы переписал это примерно так:

<?php
        header('Content-Encoding', 'chunked');
        header('Transfer-Encoding', 'chunked');
        header('Content-Type', 'text/html');
        header('Connection', 'keep-alive');

        ob_flush();
        flush();

        for ($i = 0; $i < 10000; $i++) {
            $string = "string";
            echo strlen($string)."\r\n"; // this is the length
            echo $string."\r\n"; // this is the date
            echo "\r\n"; // newline between chunks
            ob_flush(); // rinse and repeat
            flush();
            sleep(2);
        } 
        echo  "\r\n"; // send final empty line
        ob_flush();
        flush();

?>

Приведенный выше код не будет работать при любых обстоятельствах (например, со строками, содержащими символы новой строки или не-ascii-кодировки), поэтому вам придется адаптировать его к вашему варианту использования.

person Jan Thomä    schedule 26.11.2012
comment
этот сценарий дает мне следующий вывод: 6 строк 6 строк 6 строк 6 строк 6 строк 6 строк 6 строк 6 строк 6 строк 6 строк (только с 10 итерациями), но передача не разделена на части. Что мне не хватает? Есть ли что-то особенное для настройки на Apache / nginx (используется как обратный прокси с директивой proxy_buffering off;) - person Jean-Marc Dormoy; 26.11.2012