Этот способ, как ни странно, поддерживается только Firefox. На момент написания Opera и Safari под Windows не поддерживали его. Он представляет собой XHR-запрос, ответ на который может быть разделен на части. При получении новой части вызывается onload().
Вот - пример, можете попробовать его в любом браузере, и увидите, изменилось ли что-то в поддержке. Эталонное поведение: Firefox.
Вот - клиентский код
function runMultipart() {
// не кросс-браузерно, все равно способ Firefox only
var req = new XMLHttpRequest();
req.multipart = true;
// асинхронный запрос
req.open("GET","/server_push/multipart.php?r="+Math.random(), true);
req.onload = function(event) {
var result = event.target.responseText
var d = document.createElement("div")
d.innerHTML = "onload:"+result;
document.getElementById('xhr_multipart_dump1').appendChild(d)
}
req.onreadystatechange = function() {
if (req.readyState!=4) return
var d = document.createElement("div")
d.innerHTML = "State:"+req.readyState+' Status:'+req.status
document.getElementById('xhr_multipart_dump1').appendChild(d)
}
req.send(null);
}
Асинхронность запроса в случае с Multipart XMLHTTPRequest - вещь довольно условная, при установке синхронности - реально браузер подвиснет только до
первой части multipart-сообщения. Думается, это самое правильное, что можно было сделать, т.к получать весь multipart-запрос синхронно никому не нужно, для этого
есть обычные запросы.
Для обработки данных, как видно из примера, в Multipart XMLHTTPRequest используется функция onload, которая получает последний кусок из event.
Есть аналогичная функция onerror, но при вызове из javascript она не работает. Поэтому для обработки ошибок используем старый добрый onreadystatechange, который
вызывается при каждом куске данных или при ошибке.
Чтобы ответить на Multipart XMLHTTPRequest, сервер должен выбрать уникальный разделитель, и первым делом - сообщить его браузеру вместе со спец. заголовком:
header('Content-type: multipart/x-mixed-replace;boundary="УнИкАлЬНЫЙРАздеЛитЕЛЬ"');
Далее сервер может слать данные, и информировать браузер о конце каждой части ответа посылкой разделителя. Перед каждой частью ответа должен быть заголовок Content-Type.
Более подробно - вот, например, серверный код из примера выше.
// уникальный разделитель, можете использовать конкат нескльких uniqid() и т.п.
$delimiter = "boundary";
header('Content-type: multipart/x-mixed-replace;boundary="'.$delimiter.'"');
// полностью отрубаем буферизацию
while (@ob_end_flush()) {}
$header = "Content-type: text/html\r\n\r\n"; // перед каждой частью
$boundary = "--{$delimiter}\n"; // между частями
$footer = "--{$delimiter}--\n"; // в конце
$max = 10;
for ($i = 1; $i <= $max; $i++){
echo $header; # Заголовок перед каждой частью ответа
echo "$i\n"; # пишем сообщение
echo $boundary; # и выводим границу между сообщениями
sleep(1);
}
// завершающее сообщение
echo $header;
echo "-1";
echo $footer;
Замечательный способ, но работает только в движке Gecko, т.е Firefox и родственные браузеры.