SSE了解一下

发布时间:2019-02-22 作者:一点通


说到Web消息推送,大家可能第一个想到的就是Websocket。的确,作为HTML5中的一种持久化协议,Websocket可以帮我们连接客户端和服务端,实时地进行双向数据传递。

但是在某些场景下我们可能不需要那么复杂的连接,也不需要指定要给谁谁谁推送数据,例如一个社区有新的帖子,需要通知每个打开网站的用户,这个时候更简单的SSE(全称Server Sent Events)就派上用场了。

SSE的客户端是通过EventSource实现的,它用于接收服务器发送的事件。它通过HTTP连接到一个服务器,以text/event-stream格式接收事件,不关闭连接。SSE是单向的,只能从服务端发送消息给浏览器端,和socket不一样,,SSE是基于HTTP协议而非其它额外的协议,并且默认支持断线重连。

使用起来也非常简单

客户端

第1步,传入一个接口地址,初始化EventSource对象

var source = new EventSource('notify')

第2步,通过onmessage接收并处理服务端推送的数据

source.onmessage = event => {
	console.log(event.data)
}

当然除了接收消息还有onopenonerror事件可用,分别在连接打开时和出现错误时触发,其次还可以定义自己的事件

source.addEventListener('myEvent', event => {
	console.log(event.data)
}, false)

服务端

接下来我们就看看如何写服务端的接口来配合客户端,当然可以用任何后端语言来写,不过作为一名前端开发,我们就用Node.js来实现,代码也不多(需要先安装Node.js)

新建app.js文件

const http = require('http')
http.createServer((req, res)=>{
	if(req.url === '/notify'){
	res.writeHead(200, {
		'Content-Type': 'text/event-stream',
		'Access-Control-Allow-Origin': '*'
	})
	setInterval(function(){
		res.write(`data:${Date.now()}\n\n`)
	}, 1000)
}
}).listen(3000)

上面的代码利用http模块创建了一个简单的HTTP服务,并监听3000端口,然后把接口地址指定为'/notify'。

其中需要注意的是,Content-Type必须为text/event-stream,这也是EventSource的硬性要求。

其次我们这里设置了'Access-Control-Allow-Origin': '*'是为了防止出现跨域问题,因为目前的开发模式一般都是前后端分离的。

这里相应的完整数据参数其实有4个

  • data:数据内容
  • id:数据标识
  • event:时间类型,默认是message事件
  • retry:浏览器重新发起连接的时间间隔(毫秒)

注意,消息末尾必须以\n\n结尾,消息内部各个参数之间用\n分隔。

比如我们给自定义事件myEvent加上推送(借助join()方法使得代码更可读)

setInterval(function(){
	res.write([
		'event: myEvent\n',
		'data: hello\n\n'
	].join(''))
}, 1000)

最后运行服务

node app.js

接下来新建一个index.html文件

<!DOCTYPE html>
<html>
	<body>
		<script>
			var source = new EventSource('http://127.0.0.1:3000/notify')
			source.onmessage = event => {
				console.log(event.data)
			}
		</script>
	</body>
</html>

然后在浏览器中打开index.html文件,在F12 Console中就可以看到结果了。目前IE是不支持EventSource的,不过油相应的polyfill可用。

可见,SSE不针对谁,更适合与用户无关的消息推送。而Websocket则更强大,更适合实现类似的聊天室的功能,可定向推送。不同的场景应该选择最合适的技术。