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
```
两种情况会导致浏览器重新发起连接:
- 一种是时间间隔到期,
- 二是由于网络错误等原因,导致连接出错。
';