Как сбросить текущий вывод в RApache?
Я тестирую использование RApache в качестве SSE (Server Sent Events) и аналогичного (длинный опрос, комета и т. Д.) Серверной части. Кажется, я застрял на том, как очистить мой вывод. Является ли это возможным?
Вот мой тестовый скрипт R:
setContentType("text/plain")
repeat{
cat(format(Sys.time()),"\n")
#sendBin(paste(format(Sys.time()),"\n"))
flush(stdout())
Sys.sleep(1)
}
Моя запись в Rapache.conf:
<Location /rtest/sse>
Options -MultiViews
SetHandler r-handler
RFileHandler /var/www/local/rtest/sse.r
</Location>
И я проверяю это, используя wget или curl:
wget -O - http://localhost/rtest/sse
curl http://localhost/rtest/sse
Оба просто сидят там, что означает, что ничего не отправляется.
С помощью sendBin()
не сделал никаких изменений, и ни один не использовал flush()
,
Если я изменю repeat
в for(i in 1:5)
затем он сидит там в течение 5 секунд, а затем показывает 5 временных меток (с интервалом в одну секунду). Итак, я считаю, что все остальное работает нормально, и это чисто буферная проблема.
ОБНОВЛЕНИЕ: Глядя на это свежим взглядом через 5 месяцев, я думаю, что мог бы описать проблему более четко: проблема в том, что RApache, похоже, буферизует весь вывод и ничего не отправляет, пока скрипт R не завершится. Чтобы быть полезным для потоковой передачи, он должен каждый раз отправлять данные из Apache и на клиент flush()
называется, т. е. пока R-скрипт еще работает. Итак, мой вопрос: есть ли способ заставить RApache так себя вести?
ОБНОВЛЕНИЕ 2 Я попытался добавить flush.console()
до или после flush(stdout())
но без разницы Я тоже пробовал setStatus(status=200L)
на вершине. И я попробовал SERVER$no_cache=T;SERVER$no_local_copy=T;
в верхней части сценария. Снова это не имело никакого значения. (Да, ни один из них не должен был помочь, но это никогда не повредит!)
Вот ссылка на то, как PHP реализует сброс при работе в качестве модуля Apache: http://git.php.net/?p=php-src.git;a=blob;f=sapi/apache2handler/sapi_apache2.c Я думаю, что ключевым моментом является то, что есть вызов ap_rflush(r)
, Я предполагаю, что RApache не делает ap_rflush()
вызов.
1 ответ
Вы передаете неправильный тип MIME. Попробуйте изменить с
setContentType("text/event-stream")
EDIT1:
это попытка (все еще безуспешная), о которой я упоминал в комментарии ниже, реализовать SSE в Rook
,
<%
res$header('Content-Type', 'text/event-stream')
res$header('Cache-Control', 'no-cache')
res$header('Connection', 'keep-alive')
A <- 1
sendMessage <- function(){
while(A<=4){
cat("id: ", Sys.time(), "\n", "data: hello\n\n", sep="")
A <- A+1
flush(stdout())
Sys.sleep(1)
}
}
-%>
<% sendMessage() %>
while
условие цикла должно было быть всегда TRUE
но у меня та же проблема, поэтому мне пришлось сделать конечный цикл...
Хорошая новость в том, что у меня есть данные, поступающие в браузер. Я могу сказать, посмотрев, в инструментах разработчика, на Content-Length
в Response Header
раздел. в приведенном выше коде указано 114, и вы меняете "Hello" на "Hello!". это скажет 118.
Код js: (вам также понадобится JQuery)
$(document).ready(function(){
$("button").click(function(){
var source = new EventSource("../R/sse.Rhtml");
source.onopen = function(event){
console.log("readyState: " + source.readyState);
}
source.onmessage = function(event){
$("#div").append(event.data);
};
source.onerror = function(event){
console.log(event);
};
});
});
Итак, по существу
1) Соединение открыто (readyState 1)
2) Буферизация все еще там
3) Данные (после буферизации) достигают браузера, но при их правильном получении происходит ошибка.
EIDT2:
Интересно отметить, что brew() в вышеупомянутом файле.Rhtml вывод не буферизуется. На веб-сервере должна быть конфигурация (внутренняя R и Apache), которая буферизует потоки данных.
Как примечание стороны, flush
даже не нужно, cat
по умолчанию выводится stout()
, Итак, варианты:
- Конфигурация веб-сервера
- R-эквивалент PHP
ob_flush();
который всегда используется в любой реализации PHP, которую я видел. это пример