SSE及相关技术(web sockets, long polling等)
server-sent events--One Way Messaging
允许网页获得来自服务器的更新,并且自动更新
- Server-Sent Events: allow a web page to get updates from a server
- This was also possible before, but the web page would have to ask if any updates were available. With server-sent events, the updates come automatically.
- Examples: Facebook/Twitter updates, stock price updates, news feeds, sport results, etc.
原理如下:
- client利用regular http请求webpage
- 请求的webpage 执行javascript脚本,open a connection to server.
-
当有新的信息时服务器将信息发送给client
浏览器支持情况:
desktop:
mobile:
使用入门:
receive Server-Sent Event Notifications: (接收Server-sent事件通知)
利用EventSource的onmessage获取消息
EventSource事件如下:
onopen 当服务器连接被打开时 When a connection to the server is opened
onmessage 当接收到消息 When a message is received
onerror
创建和关闭
var source = new EventSource(); source.close();
数据格式:
data: My message\n\n
如果数据比较长时,可以采用多行data:然后使用event.data.split('\n').join('')组合数据
data: first line\n
data: second line\n\n
简单例子:
eg:html页面:
<!DOCTYPE html> <html> <head> <style> div{ border-radius: 10px; border: 2px solid pink; } </style> </head> <body> <h1></h1> <div id="result"></div> <script> if(typeof(EventSource)!=="undefined") //监测是否支持EventSource { var source=new EventSource("sseServer.jsp"); source.onmessage=function(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>
服务器sseServer.jsp代码:
<%@ page language="java" contentType="text/event-stream; charset=UTF-8" pageEncoding="UTF-8"%> <%@ page import="java.util.Date"%> <%@ page import="java.io.*"%> <% Date date = new Date(); System.out.println(date); response.setContentType("text/event-stream"); //设置contentType response.setHeader("Cache-Control", "no-cache"); //设置不缓存 response.setHeader("Pragma","no-cache"); response.setDateHeader("Expires",0); PrintWriter pw = response.getWriter(); pw.print("data: today is "+date.toString()+" wish you happy~~~"); //注意必须以data:开头 pw.flush(); %>
结果:
eg2:传送多行数据:
if(typeof(EventSource)!=="undefined"){ var source=new EventSource("multiLineServer.jsp"); source.onmessage=function(event) { document.getElementById("result").innerHTML+=event.data.split('\n').join('') + "<br />"; }; }else{ document.getElementById("result").innerHTML="Sorry, your browser does not support server-sent events..."; }
Date date = new Date(); System.out.println(date); response.setContentType("text/event-stream"); response.setHeader("Cache-Control", "no-cache"); response.setHeader("Pragma","no-cache"); response.setDateHeader("Expires",0); PrintWriter pw = response.getWriter(); pw.println("data: today is "+date.toString()+" wish you happy~~~"); pw.println("data: have a nice day"); pw.flush();
结果如下:
eg3:以json格式封装数据:
if(typeof(EventSource)!=="undefined"){ var source=new EventSource("jsonServer.jsp"); source.onmessage=function(event) { var data = JSON.parse(event.data); document.getElementById("result").innerHTML+="date:"+data.date + "<br />"; document.getElementById("result").innerHTML+="name:"+data.name + "<br />"; }; }else{ document.getElementById("result").innerHTML="Sorry, your browser does not support server-sent events..."; }
server:
Date date = new Date(); System.out.println(date); response.setContentType("text/event-stream"); response.setHeader("Cache-Control", "no-cache"); response.setHeader("Pragma","no-cache"); response.setDateHeader("Expires",0); PrintWriter pw = response.getWriter(); pw.println("data: {"); pw.println("data: \"date\":\""+date.toString()+"\","); pw.println("data: \"name\":\"wish\""); pw.println("data:}"); pw.flush();
结果如下:
添加监听事件:
事件如下:
message
open
error
eg:
if(typeof(EventSource)!=="undefined"){ var source=new EventSource("sseServer.jsp"); source.addEventListener('message',function(event){ //Connection was opended document.getElementById("result").innerHTML+=event.data + "<br />"; },false); }else{ document.getElementById("result").innerHTML="Sorry, your browser does not support server-sent events..."; }
服务器端代码相同,结果与上例相同:
open和error事件如下:
source.addEventListener('open', function(event) { // Connection was opened. }, false); source.addEventListener('error', function(event) { if (event.readyState == EventSource.CLOSED) { // Connection was closed. } }, false);
注意:当连接关闭时,浏览器会自动在3秒后重新连接,可以在服务器端设置时间
设置事件id和reconnect time
设置id
在stream前加上id:, 可以让浏览器跟踪最后一次触发的事件,如果服务器死掉时,可以在新的请求设置HTTP header,通过event.lastEventId可以获取该值
eg:
id: 1222\n
data: ...\n
设置reconnection time
默认是在连接关闭3秒后reconnect,可以通过设置stream更改
eg:设置5秒
retry: 50000\n
data: ......\n
自定义事件名称
eg:设置update事件
stream:
event: update\n
data: {"username": "wish", "emotion": "happy"}\n
js:
source.addEventListener('update', function(event) { var data = JSON.parse(event.data); console.log(data.username + ' is now ' + data.emotion); }, false);
Security
在stream中增加origin
source.addEventListener('message', function(event) { if (event.origin != 'http://cnblogs.com') { //................ return; } ... }, false);
其他请参考:Cross-document messaging security
polling相关技术比较
Regular http:
- client发送请求.
- server计算
- server sends the response to the client.
AJAX Polling:
- client利用regular http请求webpage
- 请求的webpage 执行javascript脚本以一定间隔向服务器请求file
- server计算每个reqponse,发送给client
AJAX Long-Polling:
- client利用regular http请求webpage
- 请求的webpage 执行javascript脚本向服务器请求file
- 服务器并不立即响应,而是等到有新的信息时才响应
- client收到response后立即发送新的请求,重复上面过程
HTML5 Websockets:
- client利用regular http请求webpage
- 请求的webpage 执行javascript脚本,open a connection to server.
-
有新的信息时服务器和客户端可以相互发送信息(Real-time traffic from the server to the client and from the client to the server)
- 使用请查看:https://developer.mozilla.org/en-US/docs/WebSockets/Writing_WebSocket_client_applications
Comet:
Comet 是HTML5技术之前使用streaming 和long-polling来实现实时应用程序的技术(Streaming and long polling for responsive communication between your server and client)更多了解: http://www.ibm.com/developerworks/web/library/wa-reverseajax1/index.html
Comet is a web application model where a request is sent to the server and kept alive for a long time, until a time-out or a server event occurs. When the request is completed, another long-lived Ajax request is sent to wait for other server events. With Comet, web servers can send the data to the client without having to explicitly request it.
相关博文:HTML5 Web socket和socket.io
参考:http://www.w3schools.com/html/html5_serversentevents.asp
http://jaxenter.com/tutorial-jsf-2-and-html5-server-sent-events-42932.html
http://www.html5rocks.com/en/tutorials/eventsource/basics/
http://www.whatwg.org/specs/web-apps/current-work/multipage/comms.html#authors
http://www.ibm.com/developerworks/web/library/wa-reverseajax1/index.html