通信技术:SSE设计方案(一)--- 前端Server-Sent Events概念讲解和基础类库完善发布...

本文深入浅出地介绍了Server-Sent Events (SSE) 技术,一种基于HTTP协议的服务器推送方式,适用于前端开发中服务器向客户端单向推送数据的场景。文章详细探讨了SSE的工作原理、客户端和服务端的实现细节,并讨论了与WebSocket等其他通信技术的对比。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

好了,开篇还是要扯扯的,否则感觉这个技术讲的么有那么冻人,嗯,这个晚上是有点冷了,秋衣秋裤大家都该加起来了,反正我不帮你买,妹子除外,嘻嘻。

之前几篇博客,研究前端通信技术的第一层ajax技术,从最基础的东西开始开发兼容,然后到最近的1.6版本吧,前前后后几乎将ajax的所有能用的技术都研究过一遍了,在github上也得到了120+的star,在这里我要感谢大家的支持。主要这里为什么会这样说呢,因为之前得到大家的认可和鼓励,所以这次将进行前端通信技术的第二个阶段的研究了,也就是前端的服务器推送 --- Server-Sent Events技术的研究。夜深了,不扯太多废话了,我们直接进入主题。

概念讲解:

  Server-Sent Events:简称SSE技术,也是前端es5支持的一种基于http协议的服务器推送技术。

  EventSource:js中承载SSE技术的主要核心方案和方法

  单工通道:只能一方面的数据导向,例如,在我们前端,我们通过浏览器向服务器请求数据,但是服务器不会主动推送数据给我们,这就是单通道

  双工通道:类似webSocket这样的技术,客户端可以推数据给服务器,服务器也可以推数据给客户端(下个版本实现)

  定点推送:服务器可以将数据针对单个客户端推送(下个版本实现)

  多人推送:服务器可以将数据一次性推送给所有人(下个版本实现)

 

兼容性(看下图):

  

 在所有IE系列中都不支持,其他浏览器几乎都可以实现,所以为了实现万恶的IE,会有如下2种方案

  1.  在其他浏览器上使用原生 EventSource 对象,而在 IE 上则使用简易轮询或 COMET 技术来实现;
  2.  使用 polyfill 技术,即使用第三方提供的 JavaScript 库来屏蔽浏览器的不同。本文使用的是 polyfill 技术,只需要在页面中加载第三方 JavaScript 库即可。应用本身的浏览器端代码并不需要进行改动。

  所以,这个方案,我会在最后一个版本和博客专门做兼容,暂时我们就忽略这个兼容性问题

  

对于其他通信技术的比较(也就是什么时候做这样的技术选型)

  • sse是基于http协议的,对于现有项目的改造和支持是成本最低的方案。webSocket需要前后端全都换上新的协议支持
  • 对于推送的频率来说,针对小于1次/1的推送,sse的使用最合适。大于1次的使用不划算,建议webSocket(考虑成本)
  • WebSocket 技术也比较复杂,包括服务器端和浏览器端的实现都不同于一般的 Web 应用。
  • 对于轮询来说的话,每次的http协议的创建和销毁对性能有点要求,况且对这个轮询的时间点也不是能特别好的把握

  so,sse只是针对在适合他的地方才是最好的,这些点为大家做技术选型做些参考。

 

客户端(浏览器)技术讲解:

  在客户端,也就是浏览器中,承载这个技术的就是EventSource了,下面直接上代码吧

// 通用方案
create:function (options) {         // option为可配置参数
    var param = tool.initParam(options),sendData = '';          // 将用户参数和默认参数合并

    if (param.data){        // 判断是否传递参数给服务器,做参数处理
        tool.each(param.data, function (item, index) {
            sendData += (index + "=" + item + "&")
        });
        sendData = sendData.slice(0, -1);
    }

    var es = new EventSource(param.url+'?'+sendData);  //创建EventSource链接

    es.addEventListener('open',function (e) {   // 注册默认open事件
        param.openEvent(e)
    });

    es.addEventListener('message',function (e) {    // 注册默认message事件,如果服务器不指定回掉,则走这个
        param.messageEvent(e)
    });

    es.addEventListener('error',function (e) {      // 注册默认error事件
        param.errorEvent(e)
    });

    // 创建用户自定义事件
    if (param.customEvent.length > 0){
        tool.each(param.customEvent,function (item) {
            es.addEventListener(item.name,item.callback);
        })
    }
}

  当然客户端还有代表链接状态的参数es.readyState:

    • 相当于常量EventSource.CONNECTING,表示连接还未建立,或者连接断线。
    • 相当于常量EventSource.OPEN,表示连接已经建立,可以接受数据。
    • 相当于常量EventSource.CLOSED,表示连接已断,且不会重连。

  message回调的返回值(可自己debugger看):

    data:服务器端传回的数据(文本格式)。
    origin: 服务器端URL的域名部分,即协议、域名和端口。
    lastEventId:数据的编号,由服务器端发送。如果没有编号,这个属性为空。

  

  简单解释下:通过先new EventSource对象,建立连接,然后注册一些默认事件和自定义事件,就结束了,客户端就这么简单。主要在服务端。

 

默认参数如下(有些参数预先定义下个版本使用):

var initParam = {
    url :'',                                //所链接的服务器地址
    data:'',                                //所发送的客户端数据
    customEvent:[],                         //自定义事件 格式:[{name:'事件名称',callback:function(res){}}]
    withCredentials:false,                 //是否发送跨域凭证
    serverTimeout:60000,                    //服务器http默认超时时间   待考虑:客户端配置服务器时间,不安全
    clientConnection:3000,                  //设置浏览器重连时间,浏览器默认3s重连,
    openEvent:function () {},              //客户端开始链接的事件
    messageEvent:function () {},           //客户端接受到消息的事件(如不自定义系统默认)
    errorEvent:function () {}              //客户端错误事件
}

 

服务器讲解:

  对于建立连接的服务器,针对链接的客户端有如下返回参数:

    :这是注释        单独一个冒号,代表服务器推送的一个注释。(这个可解决http中的324,发送心跳包)

    id:11        代表数据标识符,代表当前数据的唯一标识(如果断线,客户端会在下次http head中发送这个标识,可做数据传输标记)

    data:我是谁    这个数据就是客户端所接受到的数据(可推送格式化过的json数据)

    event:myEvent    服务器返回客户端所执行事件(如不定义默认执行message事件)  

    retry:3000      客户端在http超时断开后多长时间重新连接

 

  对于服务器的这些参数的互相组合,是不是突然有种脑洞大开的感觉,下个版本将在这些参数中做文章,实现开头所说的各种花样技术

 

对于做测试中发现的许多问题抛出,可能你也会想到,这些问题都将在下几个版本做完善

  • 客户端兼容性问题(这个后面做)
  • 客户端重连时间中,是否会丢失数据
  • 服务器的http协议超时时间的设置
  • 对于链接中出现的服务器返回超时
  • 如何做到单点推送,群推送
  • 服务器如何丢弃已断开的链接
  • .......

 

测试如下(跳过ie系列)

  chrome:

   

  火狐:

  

  opera:

  

  safair:暂时没有mac支持,淡定

 

所有都上传github了,可直接拉去github上的东西做测试,地址:https://github.com/GerryIsWarrior/SSE不要忘记点颗star支持我,至少得到了你的认可,我会继续研究下去。

  js-ommon:为一般开发使用,直接引入js文件的

  js-node:为node代码,做简易服务器用的

  js-npm:发的npm打包代码,可npm i sse-js / yarn add sse-js 安装

  index.html:为测试html页面

 

总结:

这篇博客主要讲解sse技术的基础概念,因为基础概念比较多,如果和第二版本一起搞上去,博文肯定很多很多,没有耐心看下去了,所以这个博文只是让大家对这个概念有所了解,知道这个东西是什么,能做什么,有啥新奇的玩意,能解决项目的什么问题。当然,我既然研究这个技术,当然为了保证将这个类库写好,至少可以到生产上使用这个类库,当然这个路不是那么好走的,还需要不停的去研究和改正。正如我正在走的开发的路,都要我们一步一个脚印的去走的,共勉。

夜已深,大家晚安,明天发表这个博客...

转载于:https://www.cnblogs.com/GerryOfZhong/p/7674483.html

### 前端 Server-Sent Events (SSE) 的实现与使用 #### 什么是 Server-Sent Events (SSE)? Server-Sent Events (SSE)种 HTML5 提供的轻量级技术,用于服务器向浏览器客户端单向推送实时数据。相比 WebSocket,SSE 更简单易用,适用于只需要从服务器到客户端的单向通信场景[^1]。 --- #### 前端 SSE 的基本用法 在前端实现 SSE 主要依靠 `EventSource` 对象。以下是其核心功能使用方法: - **创建 EventSource 连接**: 使用 `new EventSource(url)` 创建个连接实例。 - **监听消息事件**: 可以通过 `.onmessage`, `.onopen`, `.onerror` 方法处理不同的事件。 - **关闭连接**: 调用 `.close()` 方法可以手动断开连接。 以下是个简单的代码示例展示如何使用 SSE: ```javascript // 创建个新的 EventSource 实例 const eventSource = new EventSource('/sse-endpoint'); // 处理消息事件 eventSource.onmessage = function(event) { console.log('新消息:', JSON.parse(event.data)); }; // 处理连接打开事件 eventSource.onopen = function() { console.log('已建立 SSE 连接'); }; // 处理错误事件 eventSource.onerror = function(error) { console.error('发生错误:', error); }; ``` 上述代码展示了如何通过 `/sse-endpoint` URL 接收来自服务器的消息,并分别处理正常消息、连接状态以及可能发生的错误情况。 --- #### 数据格式说明 服务器返回的数据通常是纯文本形式,每条消息由特定字段组成: - `data`: 消息主体内容。 - `id`: (可选)唯标识符,用于恢复连接时同步最后条消息。 - `retry`: (可选)指定重新连接的时间间隔(毫秒单位)。 - `event`: (可选)自定义事件名称,默认为 `message`。 例如,服务器响应如下: ``` id: 123 retry: 5000 event: custom-event data: {"status": "ok", "value": 42} ``` 在这种情况下,前端会触发名为 `custom-event` 的事件而不是默认的 `message`[^2]。 --- #### 完善基础类库并进行单元测试 为了提高 SSE 功能的健壮性可维护性,可以通过封装 `EventSource` 来增强其实现逻辑。例如,添加自动重连机制或者支持多种事件类型的统管理。下面是段改进后的代码片段: ```javascript class EnhancedEventSource { constructor(url, options = {}) { this.url = url; this.options = options; this.retryInterval = options.retry || 5000; // 默认重试时间为 5 秒 this.eventSource = null; this.connect(); } connect() { if (this.eventSource && this.eventSource.readyState === EventSource.CONNECTING) { return; } this.disconnect(); // 断开旧连接 const es = new EventSource(this.url); es.onmessage = (event) => { console.log('收到消息:', event.data); }; es.onerror = () => { console.warn('尝试重新连接...'); setTimeout(() => this.connect(), this.retryInterval); // 自动重连 }; this.eventSource = es; } disconnect() { if (this.eventSource) { this.eventSource.close(); this.eventSource = null; } } } // 使用示例 const sseClient = new EnhancedEventSource('/api/sse', { retry: 3000 }); ``` 此封装实现了更灵活的功能扩展,比如设置自定义重试时间简化多处调用逻辑。 对于单元测试部分,则建议采用工具如 Jest 或 Mocha 配合 Sinon.js 模拟 HTTP 请求行为验证 `EnhancedEventSource` 类的行为是否符合预期。 --- #### Spring Boot 后端配合 SSE 的实现 如果需要完整的前后端交互方案,在后端可以选择基于 Java 的 Spring Boot 框架快速搭建 SSE 支持的服务接口[^3]。具体步骤包括配置依赖项、编写控制器代码等内容。 这里仅提供个简化的 REST 控制器作为参考: ```java import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import java.time.LocalDateTime; import java.util.concurrent.TimeUnit; @RestController public class SseController { @GetMapping(value = "/sse-endpoint", produces = MediaType.TEXT_EVENT_STREAM_VALUE) public Flux<String> streamEvents() throws InterruptedException { return Flux.interval(Duration.ofSeconds(1)) .map(sequence -> LocalDateTime.now().toString()); } } ``` 该例子每隔秒生成次当前时间戳并通过 SSE 发送给订阅者。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值