服务器推送事件

概述

服务器推送事件(Server-Sent Events,简称SSE),是浏览器向服务器发送一个HTTP请求后,服务器不断单向地向浏览器推送“信息”(message),本质上,这种通信是以流信息的方式完成的一次用时很长的下载。

特点

  • SSE使用HTTP协议,现有的服务器软件都支持
  • SSE属于轻量级,使用简单
  • SSE默认支持断线重连
  • SSE一般只用来传送文本,二进制数据需要编码后传送
  • SSE支持自定义发送的消息类型

用法

客户端
  • EventSource 对象
    SSE的客户端API部署在EventSource对象上,使用SSE时,浏览器首先生成一个EventSource实例,向服务器发起连接

        let source;
    
        if ('EventSource' in window) {
            source = new EventSource('/api/stream');
        }
    复制代码

    EventSource可指定两个参数,urlwithCredentials
    url: EventSource实例的url属性返回连接的网址(请求地址)
    withCredentials: EventSource实例的withCredentials属性返回一个布尔值,表示当前实例是否开启CORS的withCredentials,默认值是false

  • readyState 属性
    表明连接的当前状态,可取以下值:
    0:相当于常量EventSource.CONNECTING,表示连接还未建立,或者断线正在重连
    1:相当于常量EventSource.OPEN,表示连接已经建立,可以接受数据
    2:相当于常量EventSource.CLOSED,表示连接已断,且不会重连

  • 方法
    onopen:连接一旦建立,就会触发open事件,可在onopen属性定义回调函数

    source.onopen = function(event) {
        console.log('onopen event= ', event);
    };
    
    // 另一种写法
    source.addEventListener('open', function(event) {
        console.log('onopen event= ', event);
    }, false);
    复制代码

    onerror:如果发生通信发生错误或连接中断触发error事件

    source.onerror = function(event) {
        console.log('onerror event= ', event);
    };
    
    // 另一种写法
    source.addEventListener('error', function(event) {
        console.log('onerror event= ', event);
    }, false);
    复制代码

    onmessage:客户端收到服务器发送回来的数据就会触发message事件

    source.onmessage = function(event) {
        console.log('onmessage event= ', event);
    };
    
    // 另一种写法
    source.addEventListener('message', function(event) {
        console.log('onmessage event= ', event);
    }, false);
    复制代码

    自定义事件:默认情况下,服务器发送回来的数据总是触发message事件,我们可以自定义SSE事件,这种情况下,发送回来的数据不会触发message事件

    source.addEventListener('connecttime', function(event) {
        console.log('自定义事件:', event);
    }, false);
    复制代码

    close:用于关闭SSE连接

    source.close();
    复制代码
  • 代码

const _this = this;
// 创建EventSource实例对象
const source = new EventSource('/api/stream');

// 连接一旦建立,调用该方法
source.onopen = function(event) {
    console.log('onopen= ', event);
    _this.isVisible = true;
};

// 错误
source.onerror = function(event) {
    console.log('onerror= ', event);
};

// 默认事件
source.onmessage = function(event) {
    console.log('onmessage= ', event.data);
};

// 监听自定义progress方法
source.addEventListener('progress', function(event) {
    console.log('progress= ', event);
    _this.percentage = ~~event.data;
    if (_this.percentage >= 100) {
        // 关闭连接
        source.close();
    }
}, false);
复制代码
服务端
  • 数据格式

服务端向浏览器发送的SSe数据,必须是UTF-8编码的文本,具有如下的HTTP头信息:

Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive
复制代码

Content-Type必需指定为text/event-stream

  • 字段

    每一次发送的信息,由若干个message组成,每个message之间用\n\n分隔。每个message内部由若干行组成,每一行的格式如下:

    [field]: value\n
    复制代码

    data:数据内容。

    data: message\n\n
    复制代码

    如果数据很长,可以分成多行,最后一行用\n\n分隔,中间每行用\n

    data: begin message\n
    data: continue message\n\n
    复制代码

    JSON数据:

        data: {\n
        data: data: [],\n
        data: message: '操作成功',\n
        data: status: 0\n
        data: }\n\n
    复制代码

    event:表示自定义的事件类型,默认是message事件。浏览器用addEventListener()监听。

    event: connecttime\n
    data: ${new Date()}\n\n
    复制代码

    id:数据标识符,相当于每一条数据的编号。浏览器用lastEventId属性读取这个值。一旦连接断线,浏览器会发送一个HTTP头,里面包含一个特殊的Last-Event-ID头信息,用来帮助服务端重建连接。因此,这个头信息可以被视为一种同步机制。

    retry: 指定浏览器重新发起连接的时间间隔。

    retry: 10000\n
    复制代码

    导致浏览器重新发起连接:
    ① 时间间隔到期
    ② 由于网络错误等原因,导致连接出错

  • 代码

const http = require('http');

http.createServer(function(req, res) {
    let fileName = '.' + req.url;
    if (fileName === './stream') {
        res.writeHead(200, {
            "Content-Type": "text/event-stream", // 必需
            "Cache-Control": "no-cache",
            "Connection": "keep-alive",
            "Access-Control-Allow-Origin": "*"
        });

        // 指定浏览器重新发起连接的时间间隔:10s
        res.write('retry: 10000\n');
        // 自定义事件:connecttime
        res.write(`event: connecttime\n`);
        // 自定义事件返回数据,以\n\n结束
        res.write(`data: ${new Date()}\n\n`);

        let id = 0;
        let timer = setInterval(() => {
            // 默认事件标识符
            res.write(`id: ${id++}\n`);
            // 默认事件返回数据
            res.write(`data: ${new Date()}\n\n`);
        }, 1000);

        req.connection.addListener('close', function() {
            clearInterval(timer);
        }, false);

    }
}).listen(3000, '127.0.0.1');
复制代码

浏览器支持情况

EventSource

参考资料

Server-sent events
EventSource

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享