Server-Sent Events (SSE)实现长链接,服务端单向推送
emer 发布于 2021-9-15 17:44 1392 次阅读
一、SSE 的本质
严格地说,HTTP 协议无法做到服务器主动推送信息。但是,有一种变通方法,就是服务器向客户端声明,接下来要发送的是流信息(streaming)。
也就是说,发送的不是一次性的数据包,而是一个数据流,会连续不断地发送过来。这时,客户端不会关闭连接,会一直等着服务器发过来的新的数据流,视频播放就是这样的例子。本质上,这种通信就是以流信息的方式,完成一次用时很长的下载。
SSE 就是利用这种机制,使用流信息向浏览器推送信息。它基于 HTTP 协议,目前除了 IE/Edge,其他浏览器都支持。
SSE 也有自己的优点。
- SSE 使用 HTTP 协议,现有的服务器软件都支持。WebSocket 是一个独立协议。
- SSE 属于轻量级,使用简单;WebSocket 协议相对复杂。
- SSE 默认支持断线重连,WebSocket 需要自己实现。
- SSE 一般只用来传送文本,二进制数据需要编码后传送,WebSocket 默认支持传送二进制数据。
- SSE 支持自定义发送的消息类型。
客户端:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> </head> <body> 我是接收的 <div id="app"></div> </body> </html> <script> var app = document.getElementById("app"); var url = "http://127.0.0.1:3000/stream"; var source = new EventSource(url, { withCredentials: true }); source.addEventListener( "open", function (event) { // ... console.log("open", event); }, false ); source.addEventListener( "message", function (event) { var data = event.data; console.log("[ data ]", data); // handle message var divContainer = document.createElement("div"); var pText = document.createTextNode(data); divContainer.appendChild(pText); app.appendChild(divContainer); }, false ); </script>
服务端:
var express = require("express"); var app = express(); app.use(express.static("./")); app.get("/stream", function (req, res) { var val = 1; console.log("[ req ]", req); res.writeHead(200, { "Content-Type": "text/event-stream", "Cache-Control": "no-cache", Connection: "keep-alive", "Access-Control-Allow-Origin": "*", }); res.write("retry: 10000\n"); //设置断线重连时间 res.write("event: connecttime\n"); res.write("data: " + new Date() + "\n\n"); // res.write("data: " + new Date() + "\n\n"); interval = setInterval(function () { val++; res.write("data: " + val + "-----" + new Date().getTime() + "\n\n"); }, 1000); req.connection.addListener( "close", function () { clearInterval(interval); }, false ); }); var server = app.listen(3000, function () { console.log("Example app listening on port 3000!"); });