您的位置:首页 > 其它

服务器实时通知客户端方案,服务器发送/推送事件方案(2)server event,典型例子,可以用作股票、新闻信息推送

2016-11-14 15:59 981 查看
server event是html5规范的一部分,它相比websocket使用起来更简单,对服务器的改动也最小

前端html部分

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<div id="result"></div>
<script>
if(typeof(EventSource)!=="undefined")
{
var source=new EventSource("doevent");
//打开连接
source.onopen=function(event)
{
console.log("onopen",event);
};
//错误信息
source.onerror=function(e)
{
console.log("err",e);
};
//处理接受到的消息
source.onmessage=function(event)
{
console.log("onmessage",event);
document.getElementById("result").innerHTML+=event.data + "<br />";
};
}
else
{
document.getElementById("result").innerHTML="Sorry, your browser does not support server-sent events...";
}
</script>
</body>
</html>

服务器部分,其中最主要的是

①将返回的消息头的content_type设置为text/event-stream;

②返回的格式要以“data:”开头,前端收到后也是取event.data来得到信息;

③再就是返回需要加上两个换行。否则收不到MessageEvent的返回。








@RequestMapping("/doEvent")
void doEvent(HttpServletRequest req, HttpServletResponse resp)  throws ServletException, IOException
{
resp.setContentType("text/event-stream");
resp.setHeader("expires", "-1");
resp.setHeader("cache-control", "no-cache");
String s = "data:"+new Date().toString()+"\n\n";
resp.getOutputStream().write(s.getBytes());
}


如果直接用spring 的controller返回值的的情况,会产生直接访问content_type消息头依然为text/html的情况,但是前端如果是使用的server event请求依然会得到text/stream的返回,因而不影响使用

@RequestMapping("/doevent")
@ResponseBody
String doEvent(HttpServletRequest req, HttpServletResponse rsp){
rsp.setContentType("text/event-stream");
return "data:"+new Date().toString()+"\n\n";
}



以上的介绍,大家对server event已经基本了解,并可以测试例子,的确实现了服务器往客户端推送不断消息。但其实这个经常被引用的例子在不断的建立和断开链接,成了类似前端轮询那样的机制,容易误导大家。

下面的例子是一直在连接的情况下不断的推送要描绘的位置信息,更典型也更易于理解server event的设计意图

@RequestMapping("/doevent")
void doEvent(HttpServletRequest req, HttpServletResponse resp)
{
HttpHeadTool.allowAccess(resp);
LogCore.BASE.info("{} doevent", req.getSession().getId());
resp.setContentType("text/event-stream");
resp.setHeader("expires", "-1");
resp.setHeader("cache-control", "no-cache");

int i = 0;
int r = 100; //半径
int v = 50;  //走一圈的步数

while(true){
i = (i+1)%(v*2);
if(i==0){
r += 20;
}
double angel = i*Math.PI/v;	//i 从   0到2π
int x = (int)Math.round( r* Math.cos(angel) );
int y = (int)Math.round( r* Math.sin(angel) );
String s = "data:"+x+","+y+"\n\n";

try {
resp.getOutputStream().write(s.getBytes());
} catch (Exception e) {
LogCore.BASE.error(e.getMessage());
return;
}
try {
resp.flushBuffer();//前端页面关闭或刷新
} catch (IOException e) {
LogCore.BASE.error(e.getMessage());
return;
}
try {
Thread.sleep(200);
} catch (InterruptedException e) {
LogCore.BASE.error(e.getMessage());
return;
}
}
}


前端页面

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<div id="result"></div>
<script src="http://libs.baidu.com/jquery/2.1.4/jquery.min.js"></script>
<style type="text/css">
#box-container {
position: relative;
width : 800px;
height : 600px;
}
#box {
width : 40px;
height : 40px;
background-color : #f00;
position : absolute;
}
#_lable {
width : 20px;
height : 20px;
background-color : #00f;
position : absolute;
}
#_origin {
width : 5px;
height : 5px;
background-color : #00f;
position : absolute;
}
</style>
</head>
<body>
<div class="row-fluid">
<div class="row10 offset2">
<div class="page-header">
<h1>Random Movement<small> HTML 5 server sent events sample</small></h1>
</div>
</div>
<div id="box-container" class="row10 offset2">
<div id="box"></div>
<div id="_lable"></div>
<div id="_origin"></div>
</div>
</div>
<script>
if(typeof(EventSource)!=="undefined")
{
var source=new EventSource("http://localhost:8084/doevent");
//打开连接
source.onopen=function(event)
{
console.log("onopen",event);
};
//错误信息
source.onerror=function(e)
{
console.log("err",e);
};
//处理接受到的消息
source.onmessage=function(event)
{
console.log("onmessage",event);
document.getElementById("result").innerHTML=event.data + "<br />";
document.getElementById("_lable").innerHTML=event.data + "<br />";
var pos = event.data.split(',');
x = pos[0];
y = pos[1];
o_x = Number(document.body.clientWidth)/2;
o_y = Number(document.body.clientHeight)/2;
x = Number(x) + Number(o_x);
y = Number(y) + Number(o_y);
$('#box').css({
left :  x + 'px',
top : y + 'px'
});
$('#_lable').css({
left : x + 'px',
top : y + 'px'
});
$('#_origin').css({
left : o_x + 'px',
top : o_y + 'px'
});
};
}
else
{
document.getElementById("result").innerHTML="Sorry, your browser does not support server-sent events...";
}
</script>
</body>
</html>




或者用canvas绘制

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<div id="result"></div>
<script src="http://libs.baidu.com/jquery/2.1.4/jquery.min.js"></script>
<body>
<canvas class="canvas" id ="canvas" style="background-color: red">
</canvas>
<script>
var canvas = document.getElementById("canvas");
canvas.width = document.body.scrollWidth;
canvas.height = document.body.scrollHeight;
if(typeof(EventSource)!=="undefined")
{
var source=new EventSource("http://localhost:8084/doevent");
//打开连接
source.onopen=function(event)
{
console.log("onopen",event);
};
//错误信息
source.onerror=function(e)
{
console.log("err",e);
};
//处理接受到的消息
source.onmessage=function(event)
{
console.log("onmessage",event);
document.getElementById("result").innerHTML=event.data + "<br />";
var pos = event.data.split(',');
x = pos[0];
y = pos[1];
o_x = Number(document.getElementById("canvas").clientWidth)/2;
o_y = Number(document.getElementById("canvas").clientHeight)/2;
x = Number(x) + Number(o_x);
y = Number(y) + Number(o_y);
var ctx = canvas.getContext("2d");

ctx.beginPath();
ctx.arc(x, y, 5, 0, 2 * Math.PI, false);
ctx.stroke();
};
}
else
{
document.getElementById("result").innerHTML="Sorry, your browser does not support server-sent events...";
}
</script>
</body>
</html>




bingo
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  websocket serverevent