还在用轮询吗,SSE服务端推送实现页面实时更新

简介: 最近开发一个页面碰到一个需求,需要对部分数据需要实时更新状态

背景


最近开发一个页面碰到一个需求,需要对部分数据需要实时更新状态,面对这样子的场景,我们通常有以下几个方案:

  • 轮询,利用setTimeout定时轮询
  • WebSocket,利用长链接保持与服务通讯
  • SSE,服务端推送机制

是什么


我们先简单认识一下这三者的区别:

轮询


轮询就是利用setTimeout的定时器,定时向服务器发起请求,代码如下:

let timeout = 0;
functon rollRequest(requestFunc, times, immediately){
    if(timeout !== 0){
        clearTimeout(timeout);
    }
    if(immediately){
        requestFunc && requestFunc();
    }
    timeout = setTimeout(()=>{
        requestFunc && requestFunc();
        rollRequest(requestFunc, times, false);
    }, times);
}

缺点


  • 无用请求过多,可能每次请求返回的内容都是相同
  • 实时性不可控,如果内容更新了,但是页面无法及时更新

WebSocket


针对上面轮询的缺点,WebSokcet长链接就能很好解决,如:

  • 建立链接后,当服务器发现数据发生变化后才返回
  • 可控性高,客户端和服务端都可以互相通信


具体实现代码如下:

// 客户端
const ws = new WebSocket(`wss://127.0.0.1:8081`);
ws.send("这是一条消息:" + count);
// 监听消息
ws.onmessage = function (event) {
  console.log(event.data);
}
// 关闭连接
ws.close();
// 服务端
var WebSocketServer = require('ws').Server,
wss = new WebSocketServer({ port: 8181 });
wss.on('connection', function (ws) {
    console.log('client connected');
    ws.on('message', function (message) {
        console.log(message);
    });
});

缺点


可能实现方案对于一个页面数据更新有点太重了,主要包括以下几点:

  • 需要有完整链路认证,如:鉴权、登录等
  • 心跳机制实现,前后端都需要设置
  • 前后端需要规定数据返回规范
  • 服务端需要日志记录

SSE服务端推送


SSE全称Server-sent Events,是HTML 5 规范的一个组成部分,它主要由两部分组成:

  • 第一部分是服务端和浏览器的通讯协议
  • 第二部分是前端需要利用EventSource去监听返回数据


对比WebSocket:

SSE WebSocket
单向:仅服务端能发送消息 双向:客户端、服务端双向发送
仅文本数据 二进制、文本都可
常规HTTP协议 WebSocket协议

实现一个SSE代码如下:浏览器:

<!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.0">
    <title>SSE Demo测试</title>
</head>
<body>
    <h3>SSE返回内容</h3>
    <div id="app"></div>
    <script>
        const eventSource = new EventSource('http://localhost:3000/sse');
        eventSource.onmessage = (event) => {
            document.getElementById('app').innerHTML = document.getElementById('app').innerHTML + `<p>${event.data}</p>`;
        }
    </script>
</body>
</html>

服务端:

const http = require('http')
const fs = require('fs')
// Create a server
const server = http.createServer()
// 监听路由
server.on('request', (req, res) => {
    console.log('request', req.url)
    if (req.url === '/sse') {
        // Set CORS headers
        res.setHeader('Access-Control-Allow-Origin', '*')
        res.setHeader('Access-Control-Allow-Methods', 'GET, OPTIONS')
        res.setHeader('Access-Control-Allow-Headers', 'Content-Type')
        // Set SSE headers
        res.setHeader('Content-Type', 'text/event-stream')
        res.setHeader('Cache-Control', 'no-cache')
        // Send a ping approx every 2 seconds
        res.write("retry: 10000\n\n");
        res.write("event: connecttime\n\n");
        res.write("data: 第一次发送:" + (new Date()) + "\n");
        // 模拟收到消息推送给客户端
        interval = setInterval(function () {
            res.write("data: 后续更新" + (new Date()) + "\n\n");
        }, 5000);
    }
    if (req.url === '/index.html' || req.url === '/') {
        // 如果是html文件,返回html文件
        res.setHeader('Content-Type', 'text/html')
        const html = fs.readFileSync('./public/index.html');
        res.end(html)
    }
})
// Listen
server.listen(3000, () => {
    console.log('Server started on port 3000')
})

缺点


  • 兼容性问题,但是目前绝大部分浏览器是支持的,如果不支持可以采用降级方案——轮询
  • 会长期占用一个http链接,
  • 可能会导致浏览器(chrome最大http请求数是6)无法发起其他请求,这里注意是一个坑,需要设置一个超时时间,如果长时间无返回数据更新可以关闭链接
  • 解决方案,升级到http2协议可解决http请求数限制问题,放到后面《如何搭建http2网站》讲解
  • 客户端无法主动向服务器发起请求,可能造成后续问题定位难点

总结


前端实时更新需求,有多个解决方案,下面进行总结:

  • 目前最常用的轮询,是最稳定的,但是却无法做到实时
  • WebSocket可以实时,但是需要服务端和客服端长期保持一致,如果哪一方断了将无法继续
  • SSE是服务推送,可以满足大部分场景,但是也需要谨慎使用,避免占用过多链接导致其他无法发送请求

参考资料


数据不够实时:试试长连接?

目录
相关文章
|
前端开发 Java 调度
springboot整合SSE技术开发经验总结及心得
springboot整合SSE技术开发经验总结及心得
3715 0
|
索引
UniApp 组件 u-tabs 详细讲解
UniApp 组件 u-tabs 详细讲解
3261 1
|
11月前
|
监控 前端开发 JavaScript
不用WebSocket也能搞定实时消息推送?试一试SSE吧!
在现代 Web 开发中,实时数据更新至关重要,如股票行情、聊天消息等。SSE(Server-Sent Events)是一种基于 HTTP 的简单技术,可实现服务器向客户端推送实时通知。相比 WebSocket,SSE 单向通信、易于实现且具备自动重连机制。本文通过 Go 语言与 Gin 框架,演示了如何构建 SSE 实时时间推送功能。服务端代码设置必要响应头并使用定时器发送数据,客户端通过 `EventSource` 接收并展示消息。此外,还探讨了性能优化及扩展场景,如监控仪表盘和任务进度更新,帮助开发者在实际项目中应用这一高效技术。
1050 2
不用WebSocket也能搞定实时消息推送?试一试SSE吧!
|
人工智能 Java API
MCP客户端调用看这一篇就够了(Java版)
本文详细介绍了MCP(Model Context Protocol)客户端的开发方法,包括在没有MCP时的痛点、MCP的作用以及如何通过Spring-AI框架和原生SDK调用MCP服务。文章首先分析了MCP协议的必要性,接着分别讲解了Spring-AI框架和自研SDK的使用方式,涵盖配置LLM接口、工具注入、动态封装工具等步骤,并提供了代码示例。此外,还记录了开发过程中遇到的问题及解决办法,如版本冲突、服务连接超时等。最后,文章探讨了框架与原生SDK的选择,认为框架适合快速构建应用,而原生SDK更适合平台级开发,强调了两者结合使用的价值。
14187 33
MCP客户端调用看这一篇就够了(Java版)
|
弹性计算 人工智能 应用服务中间件
一键部署开源DeepSeek并集成到企业微信
DeepSeek近期发布了两款先进AI模型V3和R1,分别适用于通用应用和推理任务。由于官方API流量过大,建议通过阿里云的计算巢进行私有化部署,以确保稳定使用。用户无需编写代码即可完成部署,并可通过AppFlow轻松集成到钉钉、企业微信等渠道。具体步骤包括选择适合的机器资源、配置安全组、创建企业微信应用及连接流,最后完成API接收消息配置和测试应用。整个过程简单快捷,帮助用户快速搭建专属AI服务。
2564 7
一键部署开源DeepSeek并集成到企业微信
|
编译器 C语言
C语言中的浮点数:深入探索与应用
C语言中的浮点数:深入探索与应用
2951 1
|
缓存 安全 Cloud Native
Nginx配置最佳实践
Nginx配置最佳实践
580 0
|
Linux C语言 iOS开发
Pyinstaller简单使用说明
PyInstaller是一个Python库,可以将Python应用程序转换为独立的可执行文件。PyInstaller支持跨平台,可以在Windows、Linux和MacOS上生成可执行文件。PyInstaller会分析Python程序,并将程序打包成一个完整的可执行文件,包括所有依赖项。此外,PyInstaller可以自动检测Python依赖库,并将其打包到可执行文件中。如果PyInstaller提供的默认打包选项不能满足你的需求,你可以通过spec文件来自定义打包选项。
1416 2
|
数据安全/隐私保护
如何配置战斧指纹浏览器和IPXProxy海外代理IP?
通过代理IP,用户可以轻松绕过地域限制,访问全球范围内的网站和服务。特别是对于跨境用户来说,需要在目标市场投放广告,而代理IP能帮助实现精准投放,快速的提升品牌或者店铺的知名度。那如何在如何在战斧指纹浏览器中设置IPXProxy海外代理IP?
1009 0