相比于WebSocket,SSE更适合轻量级

一、 前言

项目首页有一个待办任务数量和消息提醒数量 的展示(单向数据的展示 ),之前使用了定时器 ,每隔十秒钟发送一次请求到后端接口拿数据,这也就是我们常说的轮询做法

1. 轮询的缺点

我们都知道轮询的缺点有几种:

资源浪费

  • 网络带宽:频繁的请求可能导致不必要的网络流量,增加带宽消耗。
  • 服务器负载:每次请求都需要服务器处理,即使是空返回,也会增加服务器的CPU和内存负载。

用户体验

  • 界面卡顿:频繁的请求和更新可能会造成用户界面的卡顿,影响用户体验。

2. websocket的缺点

那么有没有替代轮询的做法呢? 聪明的同学肯定会第一时间想到用websocket,但是在目前这个场景下我觉得使用websocket是显得有些笨重。我从以下这几方面对比:

  1. 客户端实现
    • WebSocket 客户端实现需要处理连接的建立、维护和关闭,以及可能的重连逻辑。
    • SSE 客户端实现相对简单,只需要处理接收数据和连接关闭。
  2. 适用场景
    • WebSocket 适用于需要双向通信的场景,如聊天应用、在线游戏等。
    • SSE 更适合单向数据推送的场景,如股票价格更新、新闻订阅等。
  3. 实现复杂性
    • WebSocket 是一种全双工通信协议,需要在客户端和服务器之间建立一个持久的连接,这涉及到更多的编程复杂性。
    • SSE 是单向通信协议,实现起来相对简单,只需要服务器向客户端推送数据。
  4. 浏览器支持
    • 尽管现代浏览器普遍支持 WebSocket,但 SSE 的支持更为广泛,包括一些较旧的浏览器版本。
  5. 服务器资源消耗
    • WebSocket 连接需要更多的服务器资源来维护,因为它们是全双工的,服务器需要监听来自客户端的消息。
    • SSE 连接通常是单向的,服务器只需要推送数据,减少了资源消耗。

二、 详细对比

对于这三者的详细区别,你可以参考下面我总结的表格:

以下是 WebSocket、轮询和 SSE 的对比表格:

特性 WebSocket 轮询Polling Server-Sent Events (SSE)
定义 全双工通信协议,支持服务器和客户端之间的双向通信。 客户端定期向服务器发送请求以检查更新。 服务器向客户端推送数据的单向通信协议。
实时性 高,服务器可以主动推送数据。 低,依赖客户端定时请求。 高,服务器可以主动推送数据。
开销 相对较高,需要建立和维护持久连接。 较低,但频繁请求可能导致高网络和服务器开销。 相对较低,只需要一个HTTP连接,服务器推送数据。
浏览器支持 现代浏览器支持,需要额外的库来支持旧浏览器。 所有浏览器支持。 现代浏览器支持良好,旧浏览器可能需要polyfill。
实现复杂性 高,需要处理连接的建立、维护和关闭。 低,只需定期发送请求。 中等,只需要处理服务器推送的数据。
数据格式 支持二进制和文本数据。 通常为JSON或XML。 仅支持文本数据,通常为JSON。
控制流 客户端和服务器都可以控制消息发送。 客户端控制请求发送频率。 服务器完全控制数据推送。
安全性 需要wss://(WebSocket Secure)来保证安全。 需要https://来保证请求的安全 需要SSE通过HTTPS提供,以保证数据传输的安全。
适用场景 需要双向交互的应用,如聊天室、实时游戏。 适用于更新频率不高的场景,如轮询邮箱。 适用于服务器到客户端的单向数据流,如股票价格更新。
跨域限制 默认不支持跨域,需要服务器配置CORS。 默认不支持跨域,需要服务器配置CORS。 默认不支持跨域,需要服务器配置CORS。
重连机制 客户端可以实现自动重连逻辑。 需要客户端实现重连逻辑。 客户端可以监听连接关闭并尝试重连。
服务器资源 较高,因为需要维护持久连接。 较低,但频繁的请求可能增加服务器负担。 较低,只需要维护一个HTTP连接。

这个表格概括了 WebSocket、轮询和 SSE 在不同特性上的主要对比点。每种技术都有其适用的场景和限制,选择合适的技术需要根据具体的应用需求来决定。

三、 SSE(Server-Sent Events)介绍

我们先来简单了解一下什么是Server-Sent Events

Server-Sent Events (SSE) 是一种允许服务器主动向客户端浏览器推送数据的技术。它基于 HTTP 协议,但与传统的 HTTP 请求-响应模式不同,SSE 允许服务器在建立连接后,通过一个持久的连接不断地向客户端发送消息。

工作原理

  1. 建立连接
    • 客户端通过一个普通的 HTTP 请求订阅一个 SSE 端点。
    • 服务器响应这个请求,并保持连接打开,而不是像传统的 HTTP 响应那样关闭连接。
  2. 服务器推送消息
    • 一旦服务器端有新数据可以发送,它就会通过这个持久的连接向客户端发送一个事件。
    • 每个事件通常包含一个简单的文本数据流,遵循特定的格式。
  3. 客户端接收消息
    • 客户端监听服务器发送的事件,并在收到新数据时触发相应的处理程序。
  4. 连接管理
    • 如果连接由于任何原因中断,客户端可以自动尝试重新连接。

著名的计算机科学家林纳斯·托瓦兹(Linus Torvalds) 曾经说过:talk is cheap ,show me your code

我们直接上代码看看效果:

java代码

java 复制代码
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;


@RestController
@RequestMapping("platform/todo")
public class TodoSseController {

    private final ExecutorService executor = Executors.newCachedThreadPool();

    @GetMapping("/endpoint")
    public SseEmitter refresh(HttpServletRequest request) {
        final SseEmitter emitter = new SseEmitter(Long.MAX_VALUE);
        executor.execute(() -> {
            try {
                while (true) { // 无限循环发送事件,直到连接关闭
                   // 发送待办数量更新
                    emitter.send(SseEmitter.event().data(5));
                    // 等待5秒
                    TimeUnit.SECONDS.sleep(5);
                }
            } catch (IOException e) {
                emitter.completeWithError(e);
            } catch (InterruptedException e) {
                // 当前线程被中断,结束连接
                Thread.currentThread().interrupt();
                emitter.complete();
            }
        });
        return emitter;
    }
}

前端代码

javascript 复制代码
beforeCreate() {
    const eventSource = new EventSource('/platform/todo/endpoint');
    eventSource.onmessage = (event) => {
      console.log("evebt:",event)
    };
    eventSource.onerror = (error) => {
      console.error('SSE error:', error);
      eventSource.close();
    };

    this.$once('hook:beforeDestroy', () => {
      if (eventSource) {
      eventSource.close();
    }
    });

  },

改造后

客户端只发送了一次http请求,后续所有的返回结果都可以在event.data里面获取

总结

虽然 SSE(Server-Sent Events)因其简单性和实时性在某些场景下提供了显著的优势,比如在需要服务器向客户端单向推送数据时,它能够以较低的开销维持一个轻量级的连接,但 SSE 也存在一些局限性。例如,它不支持二进制数据传输 ,这对于需要传输图像、视频或复杂数据结构的应用来说可能是一个限制。此外,SSE 只支持文本格式的数据流 ,这可能限制了其在某些数据传输场景下的应用。还有,SSE 的兼容性虽然在现代浏览器中较好,但在一些旧版浏览器中可能需要额外的 polyfill 或者降级方案。

考虑到这些优缺点,我们在选择数据通信策略时,应该基于项目的具体需求和上下文来做出决策。如果项目需要双向通信或者传输二进制数据,WebSocket 可能是更合适的选择。

如果项目的数据更新频率不高,或者只需要客户端偶尔查询服务器状态,传统的轮询可能就足够了。

而对于需要服务器频繁更新客户端数据的场景,SSE 提供了一种高效的解决方案。

总之,选择最合适的技术堆栈需要综合考虑项目的需求、资源限制、用户体验和未来的可维护性。

=转载=

相关推荐
天宇&嘘月2 小时前
web第三次作业
前端·javascript·css
mit6.8242 小时前
[实现Rpc] 通信类抽象层 | function | using | 解耦合设计思想
c++·网络协议·rpc
小王不会写code2 小时前
axios
前端·javascript·axios
发呆的薇薇°3 小时前
vue3 配置@根路径
前端·vue.js
luckyext4 小时前
HBuilderX中,VUE生成随机数字,vue调用随机数函数
前端·javascript·vue.js·微信小程序·小程序
小小码农(找工作版)4 小时前
JavaScript 前端面试 4(作用域链、this)
前端·javascript·面试
前端没钱4 小时前
前端需要学习 Docker 吗?
前端·学习·docker
前端郭德纲4 小时前
前端自动化部署的极简方案
运维·前端·自动化
海绵宝宝_4 小时前
【HarmonyOS NEXT】获取正式应用签名证书的签名信息
android·前端·华为·harmonyos·鸿蒙·鸿蒙应用开发
卷心菜不卷Iris5 小时前
第1章大型互联网公司的基础架构——1.6 RPC服务
网络·网络协议·微服务·rpc·http协议·rpc协议