我想使用SSE将数据从服务器发送到登录到我的Web应用程序的 特定个人 客户端,此时它们的会话超时为“ clock”即将到期或有消息应该发送给所有“已连接”用户,类似于UNIX wall命令,例如“系统将在5分钟内不可用,请完成交易并注销” 。'
我在w3schools和MSDN上看到的示例会自动/定期向连接的客户端发送消息,例如传输服务器的时间。
我想避免使用ajax请求从客户端轮询服务器,以询问诸如“我仍然登录吗?”之类的问题。 (会话超时已过期)或“服务器消息是什么(如果有)?”第一个特定于用户,第二个特定于所有当前用户。
可以做到这一点吗,并且有一个如何做到这一点的例子吗?
谢谢
自从发布此问题以来,我使SSE服务器/客户端演示正常工作取得了部分成功。我说,部分成功,是因为我无法使用重试选项获得不同的工作时间。如果我不选择该选项,则客户端每三秒钟会收到一条消息。如果我包含该选项,则客户端仅会收到一条消息,并且会尝试连接服务器。这是PHP服务器端代码:
<?php
header( 'Content-Type: text/event-stream' );
header( 'Cache-Control: no-cache' );
// data: {"msg": "First message"}\ndata: {"msg": "second message"}\n\n
$r = mt_rand( 1, 10 ) * 1000;
$m = "retry interval: ${r}";
$r *= 1000;
$t = date( 'r' );
// echo "retry: ${r}" . PHP_EOL; // <==== With out this, it works!
echo "data: {\"message\" : \"${m}\"}" . PHP_EOL;
echo "data: {\"message\" : \"The server time is: ${t}\"}" . PHP_EOL;
echo PHP_EOL;
ob_flush();
flush();
?>
这是客户端代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Server-Sent Events Example</title>
</head>
<body>
<p>
<button onclick="source.close();">Stop!</button>
</p>
<h1>Getting server updates</h1>
<div id="result"></div>
<script>
// Source: https://www.html5rocks.com/en/tutorials/eventsource/basics/
if( typeof( EventSource ) !== 'undefined' ) {
// 'http://symfony.dev.iambreakinout.com/SSE_Server.php'
var source = new EventSource( 'SSE_Server.php' );
source.addEventListener(
'message',
function( event ) {
if( event.origin != window.location.origin ) {
alert( 'Cross-site scripting: message origin did not match:' +
'\r\n' +
'expected origin: ' + window.location.origin + '\r\n' +
'actual origin: ' + event.origin );
return;
}
else {
var data = [];
for( var i = 0, b = 0, e = 0, d = '';; ++i, b = e + 1 ) {
e = event.data.indexOf( "\n", b );
s = ( ( e > -1 )
? event.data.substr( b, e )
: event.data.substr( b ) );
data[ i ] = JSON.parse( s ).message;
if( e === -1 ) break;
}
document.getElementById( 'result' ).innerHTML +=
data.join( '<br>' ) + '<br>';
}
},
false );
source.addEventListener(
'open',
function( event ) {
// Connection was opened.
document.getElementById( 'result' ).innerHTML += 'Open<br>';
},
false );
source.addEventListener(
'error',
function( event ) {
var readyState;
//
// The closed ready state is seen when an error event occurs, but
// the rest are shown here as a reminder to me of the defined
// ready state constant values.
//
switch( event.currentTarget.readyState ) {
case EventSource.CONNECTING: readyState = 'Connecting'; break;
case EventSource.OPEN: readyState = 'Open'; break;
case EventSource.CLOSED: readyState = 'Closed'; break;
default: readyState = '?'; break;
}
document.getElementById( 'result' ).innerHTML += readyState +
'<br>';
},
false );
}
else {
document.getElementById("result").innerHTML =
'Sorry, your browser does not support server-sent events...';
}
</script>
<button onclick="source.close();">Stop!</button>
</body>
</html>
无需更改客户端代码并允许 echo“ retry:$ {r}”。 PHP_EOL; 语句以指定重试持续时间,导致显示正在连接后停止输出。
打开
重试间隔:3000
连接
要允许重试选项起作用,我在做错什么还是没有做?
再次感谢
好的,按原样显示的代码很好,但是当它生成间隔的随机数时,它实际上不应该具有第一个“次1000”。 (du!)。
答案 0 :(得分:0)
您需要将活动用户保持在某种数据结构中,以便能够向他们发送事件。
以下是有关NodeJS(基于https://github.com/mchaov/simple-sse-nodejs-setup/)的简单注释示例:
const http = require('http');
const msg = " - Simple SSE server - ";
const port = 5000;
// Create basic server
http.createServer(function (request, response) {
// answer only to event stream requests
if (request.headers.accept && request.headers.accept == 'text/event-stream') {
// check if the resource is what we want
// => http://domain.ext/sse
// store the user into your data structure
if (/sse/gim.test(request.url)) {
sendSSE(request, response);
}
}
else {
// if not just return that you are online and a string of text
response.writeHead(200);
response.write('Welcome to ' + msg + '@ :' + port);
response.end();
}
}).listen(port);
// Setup the SSE "service" :)
// You need to cache the "response" object per user, and then you can use the functions below to send messages whenever you desire. You can have a collection that holds all the references to the response object and decide if you want to send message to one or all.
function sendSSE(request, response) {
// Setup headers
// For ease of use: example for enabled CORS
response.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
// enabling CORS
'Access-Control-Allow-Origin': "*",
'Access-Control-Allow-Headers': 'Origin, X-Requested-With, Content-Type, Accept'
});
var id = (new Date()).toLocaleTimeString();
// send first message
constructSSE(response, id, (new Date()).toLocaleTimeString());
// send message every second and a half
setInterval(function () {
constructSSE(response, id, (new Date()).toLocaleTimeString());
}, 1500);
}
// setup simple message
// call this function with proper response you took from data structure with active users to send message to the specific user
function constructSSE(response, id, data) {
response.write('id: ' + id + '\n');
// response.write('event: ' + 'logout' + '\n'); // check this
response.write("data: " + msg + port + '\n\n');
}