现在前后端通讯的常用的方式有ajax,websocket,还有fetch。但是经常的我们会接到一些需求,比如说后端要给前端发送一些通知,前端接收到通知之后,做出相应的操作,比如说发说说之类的,当自己的朋友发一个说说的话,他也希望你这边的界面也要呈现出来,或者说当一个企业的管理员发送一个公告,你再你的电脑上面也要能够及时的响应出来,这样的需求我相信很多人都遇见过。
针对于上面的问题,我们常用的方式就是用setInterval去做轮询或者是websocket,只是前者setInterval轮询这个中间的时间间隔需要考虑好,如果事件间隔较短,这对服务器的压力比较大,如果事件较长,则有些需要立即立即做出响应的方式是做不到的。后者的websocket相对来说技技术要求有点高,实现起来比较复杂。
所以就有现在的这种方式就是Server-sent Events,也就是说服务器端给前端浏览器发送事件的方式。使用Server-sent Events其实是非常简单的。我们只需要需要在服务器端将事件流发送给前端,然后前端接收到后端所传给的事件流,然后触发事件,这是事件的捕获和监听其实和前端的事件捕获和触发是一样的。所以对于前端人员来说,这种处理方式是非常的简单的。
Server-sent Events是包含在EventSoruce对象中。我们可以通过创建一个EventSource对象,给对象中传入一个地址,也就是我们请求服务器端发送事件的地址,就创建了链接,如下所示:
var evtSource = new EventSource('/sse');
其中 '/sse' 是服务器端给的向前端发送事件的接口地址。通过get方式进行发送事件。
如果事件发送地址存在跨域问题,则,我们在创建EvenetSource对象的时候,需要制定具体的地址,比如说:
var evtSource = new EventSource('http://www.baidu.com', { withCredentials: true });
这个时候,我们的事件接收器就算是创建好了,然后通过通过onmessage来接收后台传给前端的数据,也可以通过addEventListener去创建事件的监听,但是通过addEventListener创建的事件监听是需要后端的事件发送方发送相对应的事件,才能够进行触发的。
var evtSource = new EventSource('/sse');evtSource.onmessage = function (e) { console.log(e.data)}
也就是当后端发送的内容之后就会进行触发,并且将data给打印出来,首先要提出的的是,Server-sent Events 所发送的内容都是字符串的流而且是通过utf-8的编码格式的,如果后端希望给前端发送一串json,也需要将json转化成相对应的字符串,然后在发送给前端,前端接收之后,再讲所发送的字符串转换成json,然后进行处理。
然后就是监听后端发送给前端的事件内容,不如说,我们后端给前端sent一个testEvent事件,前端通过事件接收者,去触犯相对应的事件监听,因此就有了下面的工作流程
var evtSource = new EventSource('/sse');evtSource.addEventListener('testEvent', function (e) { console.log(e)})
上面代码是前端的接收事件的放,是不是很类似,就像我们之前用的一样。
var btn = document.getElementById('button')btn.addEventListener('click', funciont (e) { console.log(e)})
我们看到了前端的处理方案,但是后端应该如何才能给我们发送事件呢,
首先我们发送内容是需要给前端设置一个mime为text/event-stream,然后在进行发送事件的内容,下面是相对应的node代码
router.get('/sse', (req, res, next)=> { res.writeHead(200, { 'Connection': 'keep-alive', 'Content-Type': 'text/event-stream', 'Cache-Control': 'no-cache' }); let data = { meg: '这是一个测试SSE的数据内容' }; setTimeout(() => { console.log(JSON.stringify(data)); res.write('data:' + JSON.stringify(data) + '\n\n'); }, 2000)})
这样就能够发送给前端一条消息,就能够触发前端的事件内容。
router.get('/sse', (req, res, next)=> { res.writeHead(200, { 'Connection': 'keep-alive', 'Content-Type': 'text/event-stream', 'Cache-Control': 'no-cache' }); let data = { meg: '这是一个测试SSE的数据内容' }; setTimeout(() => { console.log(JSON.stringify(data)); res.write('event: testEvent\n\n'); res.write('data:' + JSON.stringify(data) + '\n\n'); }, 2000)})
这个就是给前端发送图个testEvent,所传送的数据就是我们的data内容。