您现在的位置是:网站首页 > 心得笔记

SSE服务器向客户端的发送事件

盛悦2019-05-16559人围观
简介SSE是 WebSocket 的一种轻量代替方案,使用 HTTP 协议。

SSE技术:使用SSE技术可以做服务端数据推送应用


SSE ( Server-sent Events )是 WebSocket 的一种轻量代替方案,使用 HTTP 协议。

  严格地说,HTTP 协议是没有办法做服务器推送的,但是当服务器向客户端声明接下来要发送流信息时,客户端就会保持连接打开,SSE 使用的就是这种原理。


SSE与 WebSocket的区别与联系

    SSE与WebSocket作用相似,都是建立浏览器与服务器之间的通信渠道,然后服务器向浏览器推送信息。 但是WebSocket比SSE强大很多,SSE只能作为一个轻量级的消息推送方案,解决了从服务端向客户端单向推送消息的场景,而Websocket是全双工通道,可以双向通信。 SSE应用场景可以是新邮件提醒、微博更新、消息通知、监管后台的一些操作等。

    SSE 是单向通道,只能服务器向客户端发送消息,如果客户端需要向服务器发送消息,则需要一个新的 HTTP 请求。 这对比 WebSocket 的双工通道来说,会有更大的开销。这么一来的话就会存在一个「什么时候才需要关心这个差异?」的问题,如果平均每秒会向服务器发送一次消息的话,那应该选择 WebSocket。如果一分钟仅 5 - 6 次的话,其实这个差异并不大。

 在浏览器兼容方面,两者差不多。在较早之前,每当需要建立双向 Socket 时就会使用 Flash,在 移动浏览器不支持 Flash 的情况下,WebSocket 的兼容是比较难做的。

SSE 我认为最大的优势是便利:

  • 实现一个完整的服务仅需要少量的代码;

  • 可以在现有的服务中使用,不需要启动一个新的服务;

  • 可以用任何一种服务端语言中使用;

  • 基于 HTTP / HTTPS 协议,可以直接运行于现有的代理服务器和认证技术。


服务端代码

public function test () {
    date_default_timezone_set('PRC'); //设置中国时区

    header('X-Accel-Buffering: no');//不对页面进行缓存
    header('Content-Type: text/event-stream');//报头设置成事件流
    header('Cache-Control: no-cache');
    ob_end_clean();
    ob_implicit_flush(1);
    while(1){//始终为真,不停抓取执行

        $data =  [
            "id" => time(),
            "message" => '欢迎来到test,现在是北京时间'.date('Y-m-d H:i:s')
        ];

        self::returnEventData($data);
        sleep(30);// 暂停30秒
    }
}

public static function returnEventData($returnData, $event='message', $id=0, $retry=0){
    $str = '';
    if($id>0){
        $str .= "id: {$id}".PHP_EOL;
    }
    if($event){
        $str.= "event: {$event}".PHP_EOL;
    }
    if($retry>0){
        $str .= "retry: {$retry}".PHP_EOL;
    }
    if(is_array($returnData)){
        $returnData = json_encode($returnData);
    }
    $str .= "data: {$returnData}".PHP_EOL;
    $str .= PHP_EOL;
    echo $str;
}

服务器首先向客户端声明接下来发送的是事件流( text/event-stream )类型的数据,然后就可以向客户端多次发送消息。

  事件流是一个简单的文本流,仅支持 UTF-8 格式的编码。每条消息以一个空行作为分隔符。

  在规范中为消息定义了 4 个字段:

  event 消息的事件类型。客户端收到消息时,会在当前的 EventSource 对象上触发一个事件,这个事件的名称就是这个字段的值,如果消息没有这个字段,客户端的 EventSource 对象就会触发默认的 message 事件。

  id 这条消息的 ID。客户端接收到消息后,会把这个 ID 作为内部属性 Last-Event-ID,在断开重连 成功后,会把 Last-Event-ID 发送给服务器。

  data 消息的数据字段。 客户端会把这个字段解析为字符串,如果一条消息有多个 data 字段,客户端会自动用换行符 连接成一个字符串。

  retry 指定客户端重连的时间。只接受整数,单位是毫秒。如果这个值不是整数则会被自动忽略。

  一个很有意思的地方是,规范中规定以冒号开头的消息都会被当作注释,一条普通的注释(:\n\n)对于服务器来说只占 5 个字符,但是发送到客户端上的时候不会触发任何事件,这对客户端来说是非常友好的。所以注释一般被用于维持服务器和客户端的长连接


客户端代码

<!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">
    <title>演示: PHP+SSE服务器向客户端推送消息</title>
    <link rel="stylesheet" href="//cdn.bootcss.com/bootstrap/3.3.5/css/bootstrap.min.css">
    <link rel="stylesheet" type="text/css" href="css/demo.css">
</head>
<body>
<div class="container">
    <header>
        <div class="row">
            <div class="col-md-3 col-xs-12"><h1 class="logo"><a>test</a></h1></div>
            <div class="col-md-9 text-right"></div>
        </div>
    </header>
    <div class="row main">
        <div class="col-md-12">
            <div class="container" style="width: 98%; margin: 30px auto;">
                <div id="result">
                    <p>每隔30秒会收到服务端发来的消息:</p>
                </div>
            </div>
        </div>
    </div>
</div>
<script src="/admin/js/jquery.min.js?v=2.1.4"></script>
<script>
 if(typeof(EventSource)!=="undefined") { //if(EventSource)判断浏览器对SSE的支持情况
 var source = new EventSource("/test");//参数是服务端的 URL 指定 URL 创建出 EventSource 对象
 source.onmessage = function (e) {//当收到服务器发送的事件时触发
 console.log(e.data);
 if (e.data == 'null') {
                return false;
 } else {
                var edata = JSON.parse(e.data);
 $('#result').append(edata.id + ':' + edata.message + "<br/>");//把已接收的数据推入追加到#result 的元素中
 }
        };
 }else{
        alert("浏览器不支持SSE");
 }
</script>

</body>
</html>


事件:

    open :连接一旦建立,就会触发open事件,可以定义相应的回调函数

    message : 收到数据就会触发message事件
        参数对象event有如下属性:
            data:服务器端传回的数据(文本格式)。
            origin: 服务器端URL的域名部分,即协议、域名和端口。
            lastEventId:数据的编号,由服务器端发送。如果没有编号,这个属性为空。)

    error:如果发生通信错误(比如连接中断),就会触发error事件。

    自定义事件 : 服务器可以与浏览器约定自定义事件。


运行效果:

b5.png