SSE 服务端主动推浏览器

最后更新于:2022-04-02 03:29:22

[TOC] ## 概述 - HTTP 协议无法做到服务器主动推送信息。但是,有一种变通方法,就是服务器向客户端声明,接下来要发送的是流信息(streaming) - 它基于 HTTP 协议,目前除了 IE/Edge,其他浏览器都支持 优点: * SSE 属于轻量级,使用简单;WebSocket 协议相对复杂。 * SSE 默认支持断线重连,WebSocket 需要自己实现。 * SSE 一般只用来传送文本,二进制数据需要编码后传送,WebSocket 默认支持传送二进制数据。 * SSE 支持自定义发送的消息类型。 ## API ### EventSource 对象 判断是否支持 EventSource ``` if ('EventSource' in window) { // ... } ``` 初始化 ``` var source = new EventSource(url); // 如果跨域,可以设置第二个参数,是否发送cookie var source = new EventSource(url, { withCredentials: true }); ``` 属性: - readyState ``` 0:相当于常量EventSource.CONNECTING,表示连接还未建立,或者断线正在重连。 1:相当于常量EventSource.OPEN,表示连接已经建立,可以接受数据。 2:相当于常量EventSource.CLOSED,表示连接已断,且不会重连。 ``` 方法: - onopen ``` source.onopen = function (event) { // ... }; // 另一种写法 source.addEventListener('open', function (event) { // ... }, false); ``` - message ``` source.onmessage = function (event) { var data = event.data; // handle message }; // 另一种写法 source.addEventListener('message', function (event) { var data = event.data; // handle message }, false); ``` - error ``` source.onerror = function (event) { // handle error event }; // 另一种写法 source.addEventListener('error', function (event) { // handle error event }, false); ``` - close ``` source.close(); ``` - 自定义事件 ``` 开发者还可以自定义 SSE 事件,且发送回来的数据不会触发message事件 source.addEventListener('foo', function (event) { var data = event.data; // handle message }, false); ``` ### 服务器实现 1. 必须是utf-8 格式,且头信息如下 ``` Content-Type: text/event-stream Cache-Control: no-cache Connection: keep-alive ``` 2. 每一次发送的信息,由若干个message组成,每个message之间用`\n\n`分隔 3. 每个message内部由若干行组成,每一行都是如下格式 ``` [field]: value\n field类型: data event id retry ``` 3. 保持心跳:用冒号开头的行,标识注释 ``` : This is a comment ``` 示例 ``` : this is a test stream\n\n data: some text\n\n data: another message\n data: with two lines \n\n ``` #### data 字段 单行: ``` data: message\n\n ``` 多行 ``` data: begin message\n data: continue message\n\n ``` 示例:json ``` data: {\n data: "foo": "bar",\n data: "baz", 555\n data: }\n\n ``` #### id 字段 数据标识符用id字段表示,相当于每一条数据的编号 ``` id: msg1\n data: message\n\n ``` - 浏览器用lastEventId属性读取这个值。 - 一旦连接断线,浏览器会发送一个 HTTP 头,里面包含一个特殊的Last-Event-ID头信息,将这个值发送回来,用来帮助服务器端重建连接。 - 因此,这个头信息可以被视为一种同步机制。 #### event 字段 - 表示自定义的事件类型,默认是message事件 - 浏览器可以用addEventListener()监听该事件 ``` event: foo\n data: a foo event\n\n data: an unnamed event\n\n event: bar\n data: a bar event\n\n ``` - 第一条的名字是foo,触发浏览器的foo事件; - 第二条未取名,表示默认类型,触发浏览器的message事件; - 第三条是bar,触发浏览器的bar事件 示例 ``` event: userconnect data: {"username": "bobby", "time": "02:33:48"} event: usermessage data: {"username": "bobby", "time": "02:34:11", "text": "Hi everyone."} event: userdisconnect data: {"username": "bobby", "time": "02:34:23"} event: usermessage data: {"username": "sean", "time": "02:34:36", "text": "Bye, bobby."} ``` #### retry 字段 指定浏览器重新发起连接的时间间隔 ``` retry: 10000\n ``` 两种情况会导致浏览器重新发起连接: - 一种是时间间隔到期, - 二是由于网络错误等原因,导致连接出错。
';