单向音讯传递数据推送,HTML五支撑服务器发送事件

在我们常见支出中,会遇到服务端和客户端的简报,今日大家就来比较一下HTML五新特色SSE和WebSocket的用法。

SSE和WebSocket的用法和比较,ssewebsocket用法

在我们日常开发中,会遇到服务端和客户端的通讯,今天我们就来比较一下HTML5新特性SSE和WebSocket的用法。

价值观的WEB应用程序通讯时的简易时序图:

历史观的WEB应用程序通讯时的简要时序图:

一,SSE

一,SSE

澳门葡京 1

澳门葡京 2

简介

SSE(Server-Sent 伊夫nts,服务器发送事件)是环绕只读Comet 交互推出的API
只怕方式。
SSE
API允许网页获得来自服务器的翻新(HTML5),用于创造到服务器的单向连接,服务器通过那一个一连能够发送大4数量的数量。服务器响应的MIME类型必须是text/event-stream,而且是浏览器中的JavaScript
API 能解析格式输出。SSE 援助短轮询、长轮询和HTTP
流,而且能在断开连接时自动鲜明什么时候再度连接。

简介

SSE(Server-Sent 伊芙nts,服务器发送事件)是围绕只读Comet 交互推出的API
只怕方式。
SSE
API允许网页获得来自服务器的翻新(HTML5),用于成立到服务器的单向连接,服务器通过那么些延续能够发送任意数量的数码。服务器响应的MIME类型必须是text/event-stream,而且是浏览器中的JavaScript
API 能解析格式输出。SSE 辅助短轮询、长轮询和HTTP
流,而且能在断开连接时自动鲜明曾几何时再一次连接。

方今Web App中,大都有Ajax,是那样子:

现行反革命Web App中,大都有Ajax,是那样子:

客户端

//判断是否支持SSE
if('EventSource' in window){

//初始化SSE
var url="http:localhost:8080/test/push";
var source=new EventSource(url);

//开启时调用
source.onopen=(event)=>{

console.log("开启SSE");

}

//监听message事件
source.onmessage=(event)=>{

var data=event.data;

$("body").append($("<p>").text(data));

}

//监听like事件
source.addEventListener('like',function(event){

var data=event.data;

$("body").append($("<p>").text(data));
},false);

//发生异常时调用
source.onerror=(event)=>{

console.log(event);

}

 

客户端只必要一贯利用**window.EventSource**目的,然后调用该对象的对应措施就能够。

 

客户端

//判断是否支持SSE
if('EventSource' in window){

//初始化SSE
var url="http:localhost:8080/test/push";
var source=new EventSource(url);

//开启时调用
source.onopen=(event)=>{

console.log("开启SSE");

}

//监听message事件
source.onmessage=(event)=>{

var data=event.data;

$("body").append($("<p>").text(data));

}

//监听like事件
source.addEventListener('like',function(event){

var data=event.data;

$("body").append($("<p>").text(data));
},false);

//发生异常时调用
source.onerror=(event)=>{

console.log(event);

}

 

客户端只需求直接使用**window.EventSource**对象,然后调用该目标的应和措施就可以。

 

澳门葡京 3

澳门葡京 4

服务端

/**
* SSE后台controller
* @author like
*
*/
@Controller
@RequestMapping(value="/test")
public class TestSSEController {

@ResponseBody
@RequestMapping(value="/push",produces="text/event-stream;charset=UTF-8")
public String push(HttpServletResponse res){

res.setHeader("Access-Control-Allow-Origin","*");

Date date=new Date();
SimpleDateFormat sdf=new SimpleDateFormat("YYYY-MM-dd HH:mm:ss");
String nowDate=sdf.format(date);

return "data: 我是一个data 现在时间是"+nowDate+" \nevent:like\n retry:5000\n\n";

} 
}

 

出于SSE是http请求,可是又限制是三个长连接,所以要设置MIME类型为text/event-stream。重返的为字符串。

服务端

/**
* SSE后台controller
* @author like
*
*/
@Controller
@RequestMapping(value="/test")
public class TestSSEController {

@ResponseBody
@RequestMapping(value="/push",produces="text/event-stream;charset=UTF-8")
public String push(HttpServletResponse res){

res.setHeader("Access-Control-Allow-Origin","*");

Date date=new Date();
SimpleDateFormat sdf=new SimpleDateFormat("YYYY-MM-dd HH:mm:ss");
String nowDate=sdf.format(date);

return "data: 我是一个data 现在时间是"+nowDate+" \nevent:like\n retry:5000\n\n";

} 
}

 

是因为SSE是http请求,不过又限定是四个长连接,所以要安装MIME类型为text/event-stream。再次来到的为字符串。

 

 

音信的格式

服务器向浏览器发送的 SSE 数据,必须是 UTF-8 编码的文书;

每一遍发送的音讯,由若干个message组成,每个message之间用\n\n分隔。每一个message内部由若干行组成;

格式

[field]:value\n

其间田野可感觉种种

  1. data
  2. event
  3.  id
  4.  retry

data代表数量,event代表事件名称,id代表id,retry代表有个别日子轮流培训贰遍。

故此自身的服务端写的新闻就能够翻译为:事件名叫**like**,数据为**本人是1个data
今后岁月是+当前时间**,每五秒轮流培训3次

data: 我是一个data 现在时间是"+nowDate+" \nevent:like\n retry:5000\n\n

 

上面是吸收接纳新闻:

澳门葡京 5

音讯的格式

服务器向浏览器发送的 SSE 数据,必须是 UTF-八 编码的文件;

每叁遍发送的新闻,由若干个message组成,各类message之间用\n\n分隔。每种message内部由若干行组成;

格式

[field]:value\n

中间田野同志可认为三种

data代表数量,event代表事件名称,id代表id,retry代表有点时间轮流培训一回。

于是小编的服务端写的音信就足以翻译为:事件名为**like**,数据为**自己是三个data
将来日子是+当前几天子**,每5秒轮流培训一遍

data: 我是一个data 现在时间是"+nowDate+" \nevent:like\n retry:5000\n\n

 

下边是收纳新闻:

澳门葡京 6

HTML5有一个Server-Sent
伊芙nts(SSE)作用,允许服务端推送数据到客户端。(经常叫数量推送)。基于数据推送是那样的,当数据源有新数据,它立刻发送到客户端,无需等待客户端请求。那一个新数据恐怕是最音讯,最新上市股票(stock)票汇兑,来自朋友的谈天消息,天气预先报告等。

HTML5有三个Server-Sent
Events(SSE)功效,允许服务端推送数据到客户端。(平日叫数码推送)。基于数据推送是这么的,当数据源有新数据,它马上发送到客户端,无需静观其变客户端请求。这个新数据恐怕是最新闻,最新上市证券票市价,来自朋友的聊天音信,天气预先报告等。

二,Websocket

二,Websocket

澳门葡京 7

澳门葡京 8

简介

WebSocket是HTML伍伊始提供的1种在单个 TCP 连接上进展全双工通信的讨论。

 

简介

WebSocket是HTML伍起来提供的1种在单个 TCP 连接上实行全双工通讯的商业事务。

 

数据拉与推的法力是如出1辙的,用户获得新数据。但数额推送有一部分优势。
你大概听别人说过Comet, Ajax推送, 反向Ajax,
HTTP流,WebSockets与SSE是见仁见智的才具。只怕最大的优势是低顺延。SSE用于web应用程序刷新数据,无需用户做别的动作。
你大概据书上说过HTML5的WebSockets,也能推送数据到客户端。WebSockets是促成服务端特别复杂的技巧,但它是真的全双工socket,
服务端能推送数据到客户端,客户端也能推送数据回服务端。SSE专门的学业于存在HTTP/HTTPS协议,援助代理服务器与认证才具。SSE是文本协议你能随随便便的调整它。如果你必要发送大部贰进制数据从服务端到客户端,WebSocket是越来越好的挑三拣四。关于SSE与WebSocket的分别,本文下边会讲到。

数据拉与推的效果是一样的,用户得到新数据。但数据推送有一些优势。
你大概传说过Comet, Ajax推送, 反向Ajax,
HTTP流,WebSockets与SSE是见仁见智的才能。或许最大的优势是低顺延。SSE用于web应用程序刷新数据,没有须要用户做其余动作。
您或然听大人讲过HTML伍的WebSockets,也能推送数据到客户端。WebSockets是贯彻服务端尤其复杂的技巧,但它是真的全双工socket,
服务端能推送数据到客户端,客户端也能推送数据回服务端。SSE专门的学问于存在HTTP/HTTPS协议,帮助代理服务器与认证本领。SSE是文件协议你能自由的调治它。假如您供给发送大部2进制数据从服务端到客户端,WebSocket是越来越好的挑3拣4。关于SSE与WebSocket的差异,本文上面会讲到。

客户端

 

var websocket = null;
//判断当前浏览器是否支持WebSocket
if ('WebSocket' in window) {
websocket = new WebSocket("ws://localhost:8080/WebSocketTest/websocket");
}
else {
alert('当前浏览器 Not support websocket')
}

//连接发生错误的回调方法
websocket.onerror = function () {
setMessageInnerHTML("WebSocket连接发生错误");
};

//连接成功建立的回调方法
websocket.onopen = function () {
setMessageInnerHTML("WebSocket连接成功");
}

//接收到消息的回调方法
websocket.onmessage = function (event) {
setMessageInnerHTML(event.data);
}

//连接关闭的回调方法
websocket.onclose = function () {
setMessageInnerHTML("WebSocket连接关闭");
}

//监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
window.onbeforeunload = function () {
closeWebSocket();
}

//将消息显示在网页上
function setMessageInnerHTML(innerHTML) {
document.getElementById('message').innerHTML += innerHTML + '<br/>';
}

//关闭WebSocket连接
function closeWebSocket() {
websocket.close();
}

//发送消息
function send() {
var message = document.getElementById('text').value;
websocket.send(message);
}

 

可以看出客户端直接调用ws地址就足以了。

 

客户端

 

var websocket = null;
//判断当前浏览器是否支持WebSocket
if ('WebSocket' in window) {
websocket = new WebSocket("ws://localhost:8080/WebSocketTest/websocket");
}
else {
alert('当前浏览器 Not support websocket')
}

//连接发生错误的回调方法
websocket.onerror = function () {
setMessageInnerHTML("WebSocket连接发生错误");
};

//连接成功建立的回调方法
websocket.onopen = function () {
setMessageInnerHTML("WebSocket连接成功");
}

//接收到消息的回调方法
websocket.onmessage = function (event) {
setMessageInnerHTML(event.data);
}

//连接关闭的回调方法
websocket.onclose = function () {
setMessageInnerHTML("WebSocket连接关闭");
}

//监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
window.onbeforeunload = function () {
closeWebSocket();
}

//将消息显示在网页上
function setMessageInnerHTML(innerHTML) {
document.getElementById('message').innerHTML += innerHTML + '<br/>';
}

//关闭WebSocket连接
function closeWebSocket() {
websocket.close();
}

//发送消息
function send() {
var message = document.getElementById('text').value;
websocket.send(message);
}

 

能够看看客户端直接调用ws地址就能够了。

 

 

 

服务端

/**
* websocket服务
* @author like
*
*/
@ServerEndpoint("/websocket")
public class WebsocketTest {

private static int onlineCount=0;//记录当前在线人数


//确保线程安全
private static CopyOnWriteArraySet<WebsocketTest> webSocketSet=new CopyOnWriteArraySet<WebsocketTest>();

private Session session;

@OnOpen
public void onOpen(Session session){
this.session=session;
webSocketSet.add(this);
addOnlineCount();
System.out.println("有新连接加入!当前在线人数为" + getOnlineCount());
}

@OnClose
public void OnClose(){
webSocketSet.remove(this); //从set中删除
subOnlineCount(); //在线数减1
System.out.println("有一连接关闭!当前在线人数为" + getOnlineCount());    
}

@OnMessage
public void OnMessage(String message, Session session){
System.out.println("来自客户端的消息:" + message);
//群发消息
for(WebsocketTest item: webSocketSet){
try {
item.sendMessage(message);
} catch (IOException e) {
e.printStackTrace();
continue;
}
}

}

@OnError
public void OnError(Session session, Throwable error){
System.out.println("发生错误");
error.printStackTrace();    
}

public void sendMessage(String message) throws IOException{
this.session.getBasicRemote().sendText(message);
//this.session.getAsyncRemote().sendText(message);
}

public static synchronized int getOnlineCount() {
return onlineCount;
}

public static synchronized void addOnlineCount() {
WebsocketTest.onlineCount++;
}

public static synchronized void subOnlineCount() {
WebsocketTest.onlineCount--;
}
}

 

服务端

/**
* websocket服务
* @author like
*
*/
@ServerEndpoint("/websocket")
public class WebsocketTest {

private static int onlineCount=0;//记录当前在线人数


//确保线程安全
private static CopyOnWriteArraySet<WebsocketTest> webSocketSet=new CopyOnWriteArraySet<WebsocketTest>();

private Session session;

@OnOpen
public void onOpen(Session session){
this.session=session;
webSocketSet.add(this);
addOnlineCount();
System.out.println("有新连接加入!当前在线人数为" + getOnlineCount());
}

@OnClose
public void OnClose(){
webSocketSet.remove(this); //从set中删除
subOnlineCount(); //在线数减1
System.out.println("有一连接关闭!当前在线人数为" + getOnlineCount());    
}

@OnMessage
public void OnMessage(String message, Session session){
System.out.println("来自客户端的消息:" + message);
//群发消息
for(WebsocketTest item: webSocketSet){
try {
item.sendMessage(message);
} catch (IOException e) {
e.printStackTrace();
continue;
}
}

}

@OnError
public void OnError(Session session, Throwable error){
System.out.println("发生错误");
error.printStackTrace();    
}

public void sendMessage(String message) throws IOException{
this.session.getBasicRemote().sendText(message);
//this.session.getAsyncRemote().sendText(message);
}

public static synchronized int getOnlineCount() {
return onlineCount;
}

public static synchronized void addOnlineCount() {
WebsocketTest.onlineCount++;
}

public static synchronized void subOnlineCount() {
WebsocketTest.onlineCount--;
}
}

 

HTML5服务器发送事件(server-sent
event)允许网页得到来自服务器的立异
Server-Sent 事件 – 单向音讯传递
Server-Sent 事件指的是网页自动获得来自服务器的换代。
在此之前也或者做到这点,前提是网页不得不垂询是还是不是有可用的换代。通过服务器发送事件,更新能够自行到达。
事例:Twitter/照片墙 更新、估价更新、新的博文、赛事结果等。

HTML5服务器发送事件(server-sent
event)允许网页获得来自服务器的翻新
Server-Sent 事件 – 单向音讯传递
Server-Sent 事件指的是网页自动获取来自服务器的翻新。
初阶也恐怕毕其功于一役那点,前提是网页不得不垂询是还是不是有可用的翻新。通过服务器发送事件,更新可以自行达到。
事例:Twitter/Facebook 更新、估价更新、新的博文、赛事结果等。

演示

澳门葡京 9

 

后台输出:

有新连接加入!当前在线人数为1
来自客户端的消息:123
来自客户端的消息:456

 

演示

澳门葡京 10

 

后台输出:

有新连接加入!当前在线人数为1
来自客户端的消息:123
来自客户端的消息:456

 

浏览器援救(全体主流浏览器均扶助服务器发送事件,除了 Internet
Explorer。)

浏览器协理(全数主流浏览器均援救服务器发送事件,除了 Internet
Explorer。)

三,总结

SSE与WebSocket有一般成效,都以用来树立浏览器与服务器之间的通讯路子。两者的区分在于:

  • WebSocket是全双工通道,能够双向通讯,作用更加强;SSE是单向通道,只可以服务器向浏览器端发送。
  • WebSocket是三个新的磋商,须要劳务器端援助;SSE则是布局在
    HTTP磋商之上的,现存的服务器软件都帮助。
  • SSE是2个轻量级协议,相对简便易行;WebSocket是1种较重的说道,相对复杂。
  • SSE默许帮忙断线重连,WebSocket则需求格外布置。
  • SSE援助自定义发送的数据类型。
  • SSE不帮助CO哈弗S
    参数url正是服务器网站,必须与近日网页的网址在同3个网域(domain),而且协商谈端口都不能够不1致。

三,总结

SSE与WebSocket有相似功能,都以用来树立浏览器与服务器之间的通讯路子。两者的分别在于:

  • WebSocket是全双工通道,能够双向通讯,功效越来越强;SSE是单向通道,只可以服务器向浏览器端发送。
  • WebSocket是贰个新的批评,需求服务器端协理;SSE则是布置在
    HTTP磋商之上的,现存的服务器软件都补助。
  • SSE是一个轻量级协议,相对简便易行;WebSocket是1种较重的磋商,相对复杂。
  • SSE暗中认可辅助断线重连,WebSocket则须要杰出布置。
  • SSE协助自定义发送的数据类型。
  • SSE不支持CO奥德赛S
    参数url就是服务器网址,必须与日前网页的网站在同一个网域(domain),而且协商谈端口都必须一律。

在我们平常花费中,会碰到服务端和客户端的广播发表,今日大家就来相比一下HTML5新特征SSE和WebSoc…

伊夫ntSource 推送(ajax普通轮询):

伊芙ntSource 推送(ajax普通轮询):

澳门葡京 11

澳门葡京 12

管理进程:

管理进度:

客户端建设构造伊芙ntSource对象,对服务器通过http协议持续拓展呼吁。服务器对客户端的响应数据格式有肆部分组成,event,data,id,空格行。客户端接收到劳动器端的响应数据之后,依照event事件值,找到伊芙ntSource对象对应的事件监听器。

客户端建构伊夫ntSource对象,对服务器通过http协议持续进行呼吁。服务器对客户端的响应数据格式有四部分组成,event,data,id,空格行。客户端接收到劳动器端的响应数据之后,根据event事件值,找到伊夫ntSource对象对应的风云监听器。

 

 

接过 Server-Sent 事件通报
伊芙ntSource 对象用于吸收接纳服务器发送事件通报:

接受 Server-Sent 事件通报
伊芙ntSource 对象用于吸收接纳服务器发送事件通报:

    //创建一个新的 EventSource 对象,规定发送更新的页面的 URL
    var source = new EventSource("../api/MyAPI/ServerSentEvents");

    //默认支持message事件
    source.onmessage = function (event) {
        console.log(source.readyState);
        console.log(event);
    };
    //创建一个新的 EventSource 对象,规定发送更新的页面的 URL
    var source = new EventSource("../api/MyAPI/ServerSentEvents");

    //默认支持message事件
    source.onmessage = function (event) {
        console.log(source.readyState);
        console.log(event);
    };

实例分析:
  创立1个新的 伊芙ntSource 对象,然后规定发送更新的页面的U奇骏L(本例中是 “demo_sse.php”),参数url正是服务器网站,必须与近来网页的网站在同二个网域(domain),而且协商谈端口都不可能不1致
  每接收到3遍立异,就能够发生 onmessage 事件

实例分析:
  创设一个新的 伊夫ntSource 对象,然后规定发送更新的页面包车型地铁U中华VL(本例中是 “demo_sse.php”),参数url正是服务器网站,必须与当前网页的网站在同贰个网域(domain),而且协商谈端口都不可能不一致
  每接收到1回创新,就能时有发生 onmessage 事件

 

 

检查评定 Server-Sent 事件协理
以下实例,大家编辑了一段额外的代码来检验服务器发送事件的浏览器援救景况:

检查评定 Server-Sent 事件匡助
以下实例,我们编辑了一段额外的代码来检查评定服务器发送事件的浏览器扶助境况:

if(!!EventSource && typeof(EventSource)!=="undefined")
{
    // 浏览器支持 Server-Sent
    // 一些代码.....
}
else
{
    // 浏览器不支持 Server-Sent..
}
if(!!EventSource && typeof(EventSource)!=="undefined")
{
    // 浏览器支持 Server-Sent
    // 一些代码.....
}
else
{
    // 浏览器不支持 Server-Sent..
}

劳动器端代码实例
为了让地点的事例可以运作,您还索要能够发送数据更新的服务器(举例PHP、ASP、ASP.NET、Java)。
服务器端事件流的语法是卓殊轻巧的。你亟待把 “Content-Type” 报头设置为
“text/event-stream”
单向音讯传递数据推送,HTML五支撑服务器发送事件。。未来,您可以起来发送事件流了。
我只会C#,所以用 ASP.NET的MVC
里面的ApiController写了个最简易的劳务器端:

劳动器端代码实例
为了让地点的事例能够运维,您还索要能够发送数据更新的服务器(举例PHP、ASP、ASP.NET、Java)。
劳务器端事件流的语法是分外轻易的。你亟需把 “Content-Type” 报头设置为
“text/event-stream”
。未来,您能够早头阵送事件流了。
我只会C#,所以用 ASP.NET的MVC
里面包车型客车ApiController写了个最轻便易行的劳务器端:

    public class MyAPIController : ApiController
    {
        /// <summary>
        /// ...api/MyAPI/ServerSentEvents
        /// </summary>
        /// <returns></returns>
        [HttpGet, HttpPost]
        public Task<HttpResponseMessage> ServerSentEvents()
        {
            //Response.ContentType = "text/event-stream"
            //Response.Expires = -1
            //Response.Write("data: " & now())
            //Response.Flush()

            string data = "id: 123456\nevent: message\ndata: 666\n\n";

            HttpResponseMessage response = new HttpResponseMessage
            {
                //注意:ContentType = "text/event-stream"
                Content = new StringContent(data, Encoding.GetEncoding("UTF-8"), "text/event-stream")
            };

            return Task.FromResult(response);
        }
    }
    public class MyAPIController : ApiController
    {
        /// <summary>
        /// ...api/MyAPI/ServerSentEvents
        /// </summary>
        /// <returns></returns>
        [HttpGet, HttpPost]
        public Task<HttpResponseMessage> ServerSentEvents()
        {
            //Response.ContentType = "text/event-stream"
            //Response.Expires = -1
            //Response.Write("data: " & now())
            //Response.Flush()

            string data = "id: 123456\nevent: message\ndata: 666\n\n";

            HttpResponseMessage response = new HttpResponseMessage
            {
                //注意:ContentType = "text/event-stream"
                Content = new StringContent(data, Encoding.GetEncoding("UTF-8"), "text/event-stream")
            };

            return Task.FromResult(response);
        }
    }

代码解释:
  把报头 “Content-Type” 设置为 “text/event-stream”
  规定不对页面举办缓存
  输出发送日期(始终以 “data: ” 开端)
  向网页刷新输出数据

代码解释:
  把报头 “Content-Type” 设置为 “text/event-stream”
  规定不对页面实行缓存
  输出发送日期(始终以 “data: ” 起头)
  向网页刷新输出数据

 

 

EventSource 对象

澳门葡京,EventSource 对象

新生成的伊芙ntSource实例对象,有1个readyState属性,申明连接所处的动静。

新生成的伊芙ntSource实例对象,有一个readyState属性,声明连接所处的境况。

source.readyState
它能够取以下值:

source.readyState
它能够取以下值:

  0,也正是常量伊夫ntSource.CONNECTING,表示连接还未创立,可能一而再断线。

  0,相当于常量伊芙ntSource.CONNECTING,表示连接还未创设,只怕延续断线。

  1,也就是常量伊夫ntSource.OPEN,表示连接已经确立,还行多少。

  壹,也正是常量伊芙ntSource.OPEN,表示连接已经确立,还可以多少。

  2,相当于常量伊夫ntSource.CLOSED,表示连接已断,且不会重连。

  二,约等于常量伊芙ntSource.CLOSED,表示连接已断,且不会重连。

 

 

在上面包车型大巴事例中,我们采纳 onmessage
事件来获得消息。可是还能应用别的事件:
事件    描述
onopen
  当通往服务器的连天被打开
onmessage 当接收到新闻
onerror   当爆发错误

在上头的例证中,大家利用 onmessage
事件来赢得新闻。可是还足以接纳任何事件:
事件    描述
onopen
  当通往服务器的接连被展开
onmessage 当接收到新闻
onerror   当发生错误

 

 

open事件

open事件

连日壹旦确立,就能触发open事件,能够定义相应的回调函数。

老是1旦确立,就能触发open事件,能够定义相应的回调函数。

source.onopen = function(event) {
// handle open event
};

source.onopen = function(event) {
// handle open event
};

// 或者

// 或者

source.addEventListener(“open”, function(event) {
// handle open event
}, false);
message事件

source.addEventListener(“open”, function(event) {
// handle open event
}, false);
message事件

选用数量就能够触发message事件。

吸收多少就能够触发message事件。

source.onmessage = function(event) {
var data = event.data;
var origin = event.origin;
var lastEventId = event.lastEventId;
// handle message
};

source.onmessage = function(event) {
var data = event.data;
var origin = event.origin;
var lastEventId = event.lastEventId;
// handle message
};

// 或者

// 或者

source.addEventListener(“message”, function(event) {
var data = event.data;
var origin = event.origin;
var lastEventId = event.lastEventId;
// handle message
}, false);
参数对象event有如下属性:

source.addEventListener(“message”, function(event) {
var data = event.data;
var origin = event.origin;
var lastEventId = event.lastEventId;
// handle message
}, false);
参数对象event有如下属性:

data:服务器端传回的数量(文本格式)。

data:服务器端传回的数码(文本格式)。

origin: 服务器端U君越L的域名部分,即协议、域名和端口。

origin: 服务器端U奥迪Q3L的域名部分,即协议、域名和端口。

last伊芙ntId:数据的数码,由劳务器端发送。借使未有编号,那一个天性为空。

last伊芙ntId:数据的数码,由服务器端发送。假如未有编号,这些天性为空。

error事件

error事件

1经发生通讯错误(比如总是中断),就能够触发error事件。

若是产生通讯错误(例如总是中断),就能触发error事件。

source.onerror = function(event) {
// handle error event
};

source.onerror = function(event) {
// handle error event
};

// 或者

// 或者

source.addEventListener(“error”, function(event) {
// handle error event
}, false);
自定义事件

source.addEventListener(“error”, function(event) {
// handle error event
}, false);
自定义事件

服务器能够与浏览器约定自定义事件。那种意况下,发送回来的数额不会触发message事件。

服务器能够与浏览器约定自定义事件。那种场馆下,发送回来的数量不会触发message事件。

source.addEventListener(“foo”, function(event) {
var data = event.data;
var origin = event.origin;
var lastEventId = event.lastEventId;
// handle message
}, false);
上边代码表示,浏览器对foo事件进展监听。

source.addEventListener(“foo”, function(event) {
var data = event.data;
var origin = event.origin;
var lastEventId = event.lastEventId;
// handle message
}, false);
地点代码表示,浏览器对foo事件实行监听。

close方法

close方法

close方法用于关闭连接。

close方法用于关闭连接。

source.close();
数码格式
概述

source.close();
数据格式
概述

服务器端发送的数目标HTTP头新闻如下:

服务器端发送的数额的HTTP头消息如下:

Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive
末端的行都以之类格式:

Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive
前面包车型客车行都以之类格式:

field: value\n
田野先生能够取七个值:“data”, “event”, “id”, or
“retry”,也正是说有肆类头消息。每便HTTP通讯能够包蕴那肆类头音信中的壹类或多类。\n代表换行符。

field: value\n
田野能够取八个值:“data”, “event”, “id”, or
“retry”,也正是说有4类头消息。每趟HTTP通讯能够涵盖那4类头音信中的1类或多类。\n代表换行符。

以冒号起初的行,表示注释。经常,服务器每隔壹段时间就能够向浏览器发送1个阐明,保持一而再不间歇。

以冒号初步的行,表示注释。平时,服务器每隔一段时间就能向浏览器发送三个讲解,保持一而再不刹车。

: This is a comment
上边是一些例证。

: This is a comment
上边是某个例子。

: this is a test stream\n\n

: this is a test stream\n\n

data: some text\n\n

data: some text\n\n

data: another message\n
data: with two lines \n\n
data:数据栏

data: another message\n
data: with two lines \n\n
data:数据栏

多少内容用data表示,能够攻下1行或多行。倘使数据唯有一行,则像下边那样,以“\n\n”结尾。

数据内容用data表示,能够攻克一行或多行。假诺数额唯有1行,则像下边那样,以“\n\n”结尾。

data: message\n\n
即便数额有多行,则最终一行用“\n\n”结尾,前面行都用“\n”结尾。

data: message\n\n
若果数量有多行,则最终壹行用“\n\n”结尾,前边行都用“\n”结尾。

data: begin message\n
data: continue message\n\n
总来说之,最终一行的data,结尾要用多少个换行符号,表示数据甘休。

data: begin message\n
data: continue message\n\n
同理可得,末了一行的data,结尾要用三个换行符号,表示数据停止。

以发送JSON格式的多寡为例。

以发送JSON格式的数目为例。

data: {\n
data: “foo”: “bar”,\n
data: “baz”, 555\n
data: }\n\n
id:数据标志符

data: {\n
data: “foo”: “bar”,\n
data: “baz”, 555\n
data: }\n\n
id:数据标志符

数量标记符用id表示,也就是每一条数据的号子。

数据标志符用id表示,约等于每一条数据的号码。

id: msg1\n
data: message\n\n
浏览器用last伊夫ntId属性读取这几个值。1旦一而再断线,浏览器会发送多少个HTTP头,里面包括一个特种的“Last-伊夫nt-ID”头新闻,将以此值发送回来,用来援救服务器端重建连接。因而,那些头消息可以被视为一种共同机制。

id: msg1\n
data: message\n\n
浏览器用last伊夫ntId属性读取那些值。1旦接二连三断线,浏览器会发送二个HTTP头,里面包含二个独特的“Last-伊芙nt-ID”头信息,将这一个值发送回来,用来帮助服务器端重建连接。因而,那么些头音信可以被视为壹种共同机制。

event栏:自定义新闻体系

event栏:自定义音信类别

event头音讯表示自定义的数据类型,大概说数据的名字。

event头消息表示自定义的数据类型,大概说数据的名字。

event: foo\n
data: a foo event\n\n

event: foo\n
data: a foo event\n\n

data: an unnamed event\n\n

data: an unnamed event\n\n

event: bar\n
data: a bar event\n\n
地点的代码创设了三条音信。第贰条是foo,触发浏览器端的foo事件;第3条未取名,表示暗中认可类型,触发浏览器端的message事件;第一条是bar,触发浏览器端的bar事件。

event: bar\n
data: a bar event\n\n
上面包车型地铁代码创设了3条音讯。第2条是foo,触发浏览器端的foo事件;第三条未取名,表示私下认可类型,触发浏览器端的message事件;第一条是bar,触发浏览器端的bar事件。

retry:最大间隔时间

retry:最大间隔时间

浏览器私下认可的是,假诺服务器端三秒内尚未发送任何音信,则开首重连。服务器端能够用retry头消息,钦点通信的最大间隔时间。

浏览器暗许的是,纵然服务器端三秒内尚未发送任何新闻,则开首重连。服务器端能够用retry头消息,钦命通讯的最大间隔时间。

retry: 10000\n

retry: 10000\n



规范
Server-sent 伊夫nts 规范是 HTML 5规范的2个组成都部队分,具体的正式文书档案见参考财富。该标准比较轻松,首要由八个部分组成:第2个部分是服务器端与浏览器端之间的电视发表协议,第一有个别则是在浏览器端可供
JavaScript 使用的 伊芙ntSource 对象。通信协议是依据纯文本的简易讨论。服务器端的响应的开始和结果类型是“text/event-stream”。响应文件的开始和结果能够视作是一个轩然大波流,由不一样的风云所构成。各个事件由项目和数目两有的组成,同时各类事件能够有2个可选的标志符。分歧事件的内容之间通过仅包涵回车符和换行符的空行(“\r\n”)来分隔。种种事件的多少或许由多行组成。代码清单
壹 给出了劳动器端响应的演示:

规范
Server-sent 伊芙nts 标准是 HTML 5规范的二个组成都部队分,具体的科班文书档案见参考财富。该标准相比较轻巧,首要由多少个部分组成:第一个部分是劳务器端与浏览器端之间的简报业协会议,第二片段则是在浏览器端可供
JavaScript 使用的 伊夫ntSource 对象。通信协议是依靠纯文本的轻便商量。服务器端的响应的从头到尾的经过类型是“text/event-stream”。响应文件的内容能够作为是三个轩然大波流,由不相同的风浪所构成。每一个事件由项目和数据两片段构成,同时每一个事件能够有多个可选的标志符。分化事件的剧情之间通过仅包罗回车符和换行符的空行(“\r\n”)来分隔。各个事件的多少只怕由多行组成。代码清单
一 给出了劳动器端响应的演示:

retry: 10000\n
event: message\n
id: 636307190866448426\n
data: 2017/05/18 15:44:46\n\n
retry: 10000\n
event: message\n
id: 636307190866448426\n
data: 2017/05/18 15:44:46\n\n

Chrome浏览器监视视图:

Chrome浏览器监视视图:

一呼百应报文底部:

响应报文底部:

澳门葡京 13

澳门葡京 14

响应报文内容:

响应报文内容:

澳门葡京 15

澳门葡京 16

种种事件之间通过空行来分隔。对于每1行来讲,冒号(“:”)前边表示的是该行的档期的顺序,冒号前边则是呼应的值。大概的类别包含:
项目为空白,表示该行是注释,会在拍卖时被忽视。
品类为 data,表示该行李包裹涵的是数量。以 data
开端的行能够出现反复。全数那么些行都以该事件的多寡。
品类为
event,表示该行用来声称事件的项目。浏览器在收到多少时,会发出相应项目标事件。
花色为 id,表示该行用来声称事件的标记符。
项目为
retry,表示该行用来声称浏览器在一连断开之后进展重复连接从前的等候时间。

各种事件时期通过空行来分隔。对于每壹行来讲,冒号(“:”)后面表示的是该行的系列,冒号后边则是相应的值。恐怕的品类包含:
类型为空白,表示该行是注释,会在管理时被忽略。
种类为 data,表示该行李包裹蕴的是数据。以 data
开首的行能够出现数次。全体这么些行都以该事件的数据。
花色为
event,表示该行用来声称事件的品种。浏览器在接受数额时,会发生相应品种的风云。
品种为 id,表示该行用来声称事件的标记符。
品类为
retry,表示该行用来声称浏览器在连接断开之后张开重复连接在此以前的等待时间。

当有多行数据时,实际的数量由每行数据以换行符连接而成。
假诺服务器端重返的数据中包蕴了事件的标记符,浏览器会记录以来2回收到到的轩然大波的标志符。假诺与劳务器端的连接中断,当浏览器端再度实行两次三番时,会通过
HTTP
头“Last-伊芙nt-ID”来声称最终一回接受到的轩然大波的标志符。服务器端能够经过浏览器端发送的事件标志符来明显从哪个事件起始来持续连接。
对于服务器端重临的响应,浏览器端须要在 JavaScript 中应用 伊夫ntSource
对象来进展拍卖。伊芙ntSource
使用的是正经的轩然大波监听器形式,只供给在目的上增加相应的事件管理方法就能够。伊夫ntSource
提供了八个标准事件:

当有多行数据时,实际的多寡由每行数据以换行符连接而成。
借使服务器端重回的多少中涵盖了事件的标志符,浏览器会记录以来3次抽出到的风云的标记符。要是与劳务器端的接连中断,当浏览器端再次张开连接时,会透过
HTTP
头“Last-伊芙nt-ID”来声称最终一回收到到的风云的标志符。服务器端能够通过浏览器端发送的轩然大波标记符来分明从哪些事件早先来继续连接。
对于服务器端再次来到的响应,浏览器端必要在 JavaScript 中接纳 伊芙ntSource
对象来开始展览拍卖。伊夫ntSource
使用的是正式的轩然大波监听器格局,只要求在目的上加上相应的事件处理方法就能够。伊夫ntSource
提供了多少个正规事件:

EventSource 对象提供的职业事件
名称   表达   事件处理方法
open   当成功与服务器创设连接时发出 onopen
message 当接受服务器发送的风浪时发出 onmessage
error   当出现谬误时发生 onerror

伊夫ntSource 对象提供的专门的学业事件
名称   表明   事件管理方法
open   当成功与服务器建设构造连接时发生 onopen
message 当接过服务器发送的风云时发生 onmessage
error   当出现错误时产生 onerror

而且,服务器端能够回来自定义类型的风云。对于这一个事件,能够利用
add伊夫ntListener 方法来增加相应的事件管理方法:

再者,服务器端能够回到自定义类型的事件。对于那么些事件,能够使用
add伊夫ntListener 方法来增加相应的事件管理方法:

var es = new EventSource('events');
es.onmessage = function(e) {
    console.log(e.data);
};

//自定义事件 myevent
es.addEventListener('myevent', function(e) {
    console.log(e.data);
});
var es = new EventSource('events');
es.onmessage = function(e) {
    console.log(e.data);
};

//自定义事件 myevent
es.addEventListener('myevent', function(e) {
    console.log(e.data);
});

在钦赐 U安德拉L 创建出 伊夫ntSource 对象之后,能够透过 onmessage 和
add伊芙ntListener
方法来加多事件管理方法。当服务器端有新的轩然大波时有发生,相应的事件管理方法会被调用。伊芙ntSource
对象的 onmessage 属性的效能类似于 add伊芙ntListener( ‘ message ’ ),可是onmessage 属性只支持2个事件处理方法。

在钦赐 UEvoqueL 成立出 伊夫ntSource 对象之后,能够通过 onmessage 和
add伊夫ntListener
方法来增多事件管理方法。当服务器端有新的事件产生,相应的事件管理方法会被调用。伊夫ntSource
对象的 onmessage 属性的功用类似于 add伊芙ntListener( ‘ message ’ ),可是onmessage 属性只帮助一个事件管理方法。

 

 

历史观的网页都以浏览器向服务器“查询”数据,可是众多场合,最实用的不贰诀即使服务器向浏览器“发送”数据。比方,每当收到新的电子邮件,服务器就向浏览器发送1个“文告”,那要比浏览器定期向服务器询问(polling)更有成效。服务器发送事件(Server-Sent
伊夫nts,简称SSE)正是为着解决这些标题,而提议的一种新API,布置在伊夫ntSource对象上。目前,除了IE,别的主流浏览器都帮助。
简单来讲说,所谓SSE,正是浏览器向服务器发送3个HTTP请求,然后服务器不断单向地向浏览器推送“音信”(message)。那种消息在格式上非常粗略,就是“音讯”加上前缀“data:
”,然后以“\n\n”结尾。

历史观的网页都是浏览器向服务器“查询”数据,不过众多场馆,最实用的方法是服务器向浏览器“发送”数据。比方,每当收到新的电子邮件,服务器就向浏览器发送3个“通知”,那要比浏览器定时向服务器询问(polling)更有效能。服务器发送事件(Server-Sent
伊芙nts,简称SSE)就是为着消除那么些标题,而提出的一种新API,布置在伊芙ntSource对象上。近日,除了IE,别的主流浏览器都支持。
简易说,所谓SSE,正是浏览器向服务器发送一个HTTP请求,然后服务器不断单向地向浏览器推送“音讯”(message)。那种音信在格式上很轻易,正是“音讯”加上前缀“data:
”,然后以“\n\n”结尾。

SSE与WebSocket有一般功效,都以用来确立浏览器与服务器之间的通信门路。两者的分别在于:

SSE与WebSocket有相似成效,都是用来创建浏览器与服务器之间的通讯门路。两者的分别在于:

  WebSocket是全双工通道,能够双向通讯,功效更加强;SSE是单向通道,只好服务器向浏览器端发送。

  WebSocket是全双工通道,能够双向通讯,功效更加强;SSE是单向通道,只可以服务器向浏览器端发送。

  WebSocket是一个新的情商,供给劳务器端支持;SSE则是铺排在HTTP协议之上的,现存的服务器软件都援助。

  WebSocket是三个新的说道,需求服务器端援救;SSE则是布局在HTTP协议之上的,现成的服务器软件都援助。

  SSE是四个轻量级协议,相对简便易行;WebSocket是1种较重的探究,相对复杂。

  SSE是叁个轻量级协议,相对简便易行;WebSocket是壹种较重的商业事务,相对复杂。

  SSE暗中认可扶助断线重连,WebSocket则需求额外安排。

  SSE暗中认可支持断线重连,WebSocket则必要额外布置。

  SSE帮忙自定义发送的数据类型。

  SSE协理自定义发送的数据类型。

从地点的可比可以看看,两者各有特点,适合区别的场馆。

从下边包车型大巴相比较能够看出,两者各有特点,适合不相同的场合。

 

 

民用完整的HTML5页面和C#(MVC实现服务端代码)如下:

民用完整的HTML5页面和C#(MVC实现服务端代码)如下:

前端HTML5页面:

前端HTML5页面:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>HTML5 服务器发送事件(Server-Sent Events)-单向消息传递</title>
    <meta name="author" content="熊仔其人" />
    <meta name="generator" content="2017-05-18" />
</head>
<body>
    <h1>获取服务端更新数据</h1>
    <div id="result"></div>

<script>
if(typeof(EventSource)!=="undefined")
{
    //创建一个新的 EventSource 对象,规定发送更新的页面的 URL
    var source = new EventSource("../api/MyAPI/ServerSentEvents");
    //默认支持open事件
    source.onopen = function (event) {
        console.log(source.readyState);
        console.log(event);
    };
    //默认支持error事件
    source.onerror = function (event) {
        console.log(source.readyState);
        console.log(event);
    };
    //默认支持message事件
    source.onmessage = function (event) {
        console.log(source.readyState);
        console.log(event);
        document.getElementById("result").innerHTML += event.data + "<br>";
    };

    //处理服务器响应报文中的自定义事件
    source.addEventListener("CustomEvent", function (e) {
        console.log("唤醒自定义事件");
        console.log(e);
        document.getElementById("result").innerHTML += e.data + "<br>";
    });
}
else
{
    document.getElementById("result").innerHTML="抱歉,你的浏览器不支持 server-sent 事件...";
}
</script>

</body>
</html>
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>HTML5 服务器发送事件(Server-Sent Events)-单向消息传递</title>
    <meta name="author" content="熊仔其人" />
    <meta name="generator" content="2017-05-18" />
</head>
<body>
    <h1>获取服务端更新数据</h1>
    <div id="result"></div>

<script>
if(typeof(EventSource)!=="undefined")
{
    //创建一个新的 EventSource 对象,规定发送更新的页面的 URL
    var source = new EventSource("../api/MyAPI/ServerSentEvents");
    //默认支持open事件
    source.onopen = function (event) {
        console.log(source.readyState);
        console.log(event);
    };
    //默认支持error事件
    source.onerror = function (event) {
        console.log(source.readyState);
        console.log(event);
    };
    //默认支持message事件
    source.onmessage = function (event) {
        console.log(source.readyState);
        console.log(event);
        document.getElementById("result").innerHTML += event.data + "<br>";
    };

    //处理服务器响应报文中的自定义事件
    source.addEventListener("CustomEvent", function (e) {
        console.log("唤醒自定义事件");
        console.log(e);
        document.getElementById("result").innerHTML += e.data + "<br>";
    });
}
else
{
    document.getElementById("result").innerHTML="抱歉,你的浏览器不支持 server-sent 事件...";
}
</script>

</body>
</html>

C#写的劳动器端:

C#写的劳务器端:

using System;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Web.Http;

namespace WebTest.Controllers
{
    /// <summary>
    /// api/{controller}/{id}
    /// </summary>
    public class MyAPIController : ApiController
    {
        static readonly Random random = new Random();

        /// <summary>
        /// ...api/MyAPI/ServerSentEvents
        /// </summary>
        /// <returns></returns>
        [HttpGet, HttpPost]
        public Task<HttpResponseMessage> ServerSentEvents()
        {
            //Response.ContentType = "text/event-stream"
            //Response.Expires = -1
            //Response.Write("data: " & now())
            //Response.Flush()

            string data = "";
            if (random.Next(0, 10) % 3 == 0)
            {
                //唤醒自定义的CustomEvent
                data = ServerSentEventData("这是自定义通知", DateTime.Now.Ticks.ToString(), "CustomEvent");
            }
            else
            {
                //唤醒默认的message
                data = ServerSentEventData(DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss"), DateTime.Now.Ticks.ToString());
            }

            HttpResponseMessage response = new HttpResponseMessage
            {
                //注意:ContentType = "text/event-stream"
                Content = new StringContent(data, Encoding.GetEncoding("UTF-8"), "text/event-stream")
            };

            return Task.FromResult(response);
        }

        public string ServerSentEventData(string data, string id, string _event = "message", long retry = 10000)
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendFormat("retry:{0}\n", retry);
            sb.AppendFormat("event:{0}\n", _event);
            sb.AppendFormat("id:{0}\n", id);
            sb.AppendFormat("data:{0}\n\n", data);
            return sb.ToString();
        }

    }
}
using System;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Web.Http;

namespace WebTest.Controllers
{
    /// <summary>
    /// api/{controller}/{id}
    /// </summary>
    public class MyAPIController : ApiController
    {
        static readonly Random random = new Random();

        /// <summary>
        /// ...api/MyAPI/ServerSentEvents
        /// </summary>
        /// <returns></returns>
        [HttpGet, HttpPost]
        public Task<HttpResponseMessage> ServerSentEvents()
        {
            //Response.ContentType = "text/event-stream"
            //Response.Expires = -1
            //Response.Write("data: " & now())
            //Response.Flush()

            string data = "";
            if (random.Next(0, 10) % 3 == 0)
            {
                //唤醒自定义的CustomEvent
                data = ServerSentEventData("这是自定义通知", DateTime.Now.Ticks.ToString(), "CustomEvent");
            }
            else
            {
                //唤醒默认的message
                data = ServerSentEventData(DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss"), DateTime.Now.Ticks.ToString());
            }

            HttpResponseMessage response = new HttpResponseMessage
            {
                //注意:ContentType = "text/event-stream"
                Content = new StringContent(data, Encoding.GetEncoding("UTF-8"), "text/event-stream")
            };

            return Task.FromResult(response);
        }

        public string ServerSentEventData(string data, string id, string _event = "message", long retry = 10000)
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendFormat("retry:{0}\n", retry);
            sb.AppendFormat("event:{0}\n", _event);
            sb.AppendFormat("id:{0}\n", id);
            sb.AppendFormat("data:{0}\n\n", data);
            return sb.ToString();
        }

    }
}

通讯在页面上的来得结果:

通讯在页面上的显示结果:

澳门葡京 17

澳门葡京 18

透过Chrome监察和控制互连网互动时序:

通过Chrome监察和控制网络互动时序:

澳门葡京 19

澳门葡京 20

由此Chrome浏览器调节台出口,上边是1轮ope、message、error事件的详细情形:

因此Chrome浏览器调节台出口,上边是一轮ope、message、error事件的详细的情况:

澳门葡京 21

澳门葡京 22

 

 

迄今结束,马到成功。

现今,大功告成。

 

 

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

*
*
Website