我不负责Apache的配置,所以我不确定在有用的conf文本方面我能提供什么,但我相当肯定我已将问题缩小到登录。在没有任何登录的情况下,EventSource在XAMPP上本地完美运行,并且在生产服务器上进行身份验证后刷新页面,但是服务器上的第一次加载将无法打开连接。以前有人见过这个问题吗?在搜索过去几天之后,我无法在互联网上找到任何。
编辑:一些代码
一些服务器端代码(主要不应该是相关的):
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
$client_stream = new RedisStream();
$client_stream->poll(1); //The loop, with sleep time as a parameter
JavaScript:
var xhttpViewSet;
var xhttpSearch;
var view = 'tile';
var search = '';
var seed_url = '/core/seed_view.php';
var stream_url = '/core/stream.php';
var default_class = 'panel-default';
var success_class = 'panel-success';
var warning_class = 'panel-warning';
var danger_class = 'panel-danger';
function UpdateClient(c_name, c_obj) {
if ((c_element = document.getElementById(c_name)) !== null) {
c_element.classList.remove('text-muted');
c_element.classList.remove(default_class);
c_element.classList.remove(success_class);
c_element.classList.remove(warning_class);
c_element.classList.remove(danger_class);
switch (c_obj['status']) {
case 0:
c_obj['status'] = 'OK';
c_element.classList.add(success_class)
break;
case 1:
c_obj['status'] = 'Warning';
c_element.classList.add(warning_class)
break;
case 2:
c_obj['status'] = 'Critical';
c_element.classList.add(danger_class)
break;
default:
c_obj['status'] = 'Unknown';
c_element.classList.add(danger_class)
break;
}
for (i in c_obj) {
var var_nodes = c_element.getElementsByClassName(i);
if (var_nodes.length > 0) {
for (var j = var_nodes.length - 1; j >= 0; j--) {
var_nodes[j].innerHTML = c_obj[i];
}
}
}
}
}
function SetView() {
var view_url = seed_url + '?search=' + search + '&view=' + view;
xhttpViewSet.open('GET', view_url, true);
xhttpViewSet.send();
}
var main = function() {
container = document.getElementById('content');
if (new XMLHttpRequest()) {
xhttpViewSet = new XMLHttpRequest();
xhttpSearch = new XMLHttpRequest();
} else {
xhttpViewSet = new ActiveXObject('Microsoft.XMLHTTP');
xhttpSearch = new ActiveXObject('Microsoft.XMLHTTP');
}
var stream = new EventSource(stream_url);
stream.onopen = function() {
console.log('Connection opened.'); //This doesn't fire
}
stream.onmessage = function(e) {
var c_obj = JSON.parse(e.data);
UpdateClient(c_obj.name, c_obj.value);
};
xhttpViewSet.onreadystatechange = function() {
if (xhttpViewSet.readyState == 4) {
var resp = xhttpViewSet.responseText;
if (xhttpViewSet.status == 200 && resp.length > 0) {
container.innerHTML = resp;
if (view == 'list') {
$('#computer-table').DataTable({
"lengthMenu": [[25, 50, 100], [25, 50, 100]]
});
}
} else {
container.innerHTML = '<error>No computers matched your search or an error occured.</error>';
}
}
}
SetView(); //This successfully does all but make the EventSource connection, and only fails to do that on first load
document.getElementById('list-view').addEventListener('click', function() {
view = 'list';
SetView();
});
document.getElementById('tile-view').addEventListener('click', function() {
view = 'tile';
SetView();
});
document.getElementById('search').addEventListener('keyup', function() {
search = this.value.toUpperCase();
SetView();
});
document.getElementById('clear-search').addEventListener('click', function() {
document.getElementById('search').value = '';
search = '';
SetView();
});
};
window.onload = main;
答案 0 :(得分:1)
如果没有更多信息,确实有点难以确定,但根据您目前所说的内容,我认为它是以下之一:
HEAD / OPTIONS :某些浏览器会在发送GET或POST之前向服务器脚本发送HEAD或OPTIONS http调用。发送OPTIONS的目的是询问允许发送哪些标头。这可能是登录过程的一部分; 可能会解释重新加载时它的工作原理。有关详细信息,请参阅使用HTML5 SSE的数据推送应用程序的第9章(免责声明:我的书);基本上,在SSE脚本的顶部,您需要检查$_SERVER["REQUEST_METHOD"]
的值,如果它是"OPTIONS"
,请拦截并说明您要接受的标题。我之前使用过这个:
header("Access-Control-Allow-Headers: Last-Event-ID,".
" Origin, X-Requested-With, Content-Type, Accept,".
" Authorization");`
CORS: HTML网页网址和SSE网页网址必须具有相同的来源。在数据推送应用程序的第9章(再次)中有详细的解释(特定于SSE),或者Wikipedia(不太具体)。如果这是问题所在,请考虑将header("Access-Control-Allow-Origin: *");
添加到您的SSE脚本中。
withCredentials: SSE构造函数有第二个参数,你可以这样使用它:var stream = new EventSource(stream_url, { withCredentials: true });
它说可以发送auth凭证。 (同样,本书的第9章更详细 - 抱歉重复的插件!)在服务器端还有第二步:在PHP SSE脚本的顶部,您需要添加以下内容。
header("Access-Control-Allow-Origin: ".@$_SERVER["HTTP_ORIGIN"]);
header("Access-Control-Allow-Credentials: true");
PHP会话锁定:这通常会导致相反的问题,即SSE脚本已锁定PHP会话,因此没有其他PHP脚本可以工作。有关如何处理它,请参阅https://stackoverflow.com/a/30878764/841830。 (无论如何,这是一个好主意,即使它不是你的问题。)