文章目录
- 前言
- 一、SSE简介
- 1、SSE特点
- Polyfill
 
- 2、SSE原理
- 3、SSE技术实现:
- 4、SSE应用场景:
- 5、EventSource
 
- 二、SSE使用
- 1、前端
- 2、后端
- 3、完整代码
- 前端
- 后端
 
 
- 总结
前言
本文主要记录SSE通讯的简介、使用、以及原理和一个ChatGPT返回数据的demo。
一、SSE简介
SSE(Server-Sent Events,服务器推送事件)是一种用于在浏览器和服务器之间实现实时、单向通信的Web技术。它允许服务器向客户端推送数据,而无需客户端发起请求。与传统的HTTP请求-响应模式不同,SSE建立了一种持久的连接,通过这个连接,服务器可以随时向客户端发送更新的数据。这种实时通信的方式非常适用于需要实时更新数据的应用,如聊天应用、股票行情、实时监控等。
1、SSE特点
- 简单易用:SSE使用简单的API,只需要创建EventSource对象并监听事件即可实现实时通信。
- 单向通信:SSE是一种单向通信方式,只允许服务器向客户端推送数据,而不支持客户端向服务器发送请求。
- 实时性:SSE建立了持久连接,服务器可以随时向客户端发送更新的数据,实现实时的数据推送。
- 自动重连:如果连接中断,SSE会自动尝试重新建立连接,确保持久连接的稳定性。
- 支持事件流:SSE使用事件流(event stream)的格式来传输数据,可以发送不同类型的事件,方便客户端进行处理。
需要注意的是,SSE在一些旧版本的浏览器中可能不被完全支持。但是,大多数现代浏览器都支持SSE,并且可以通过Polyfill来提供兼容性支持。
Polyfill
Polyfill是一种用于填充浏览器或环境中缺少的功能或API的代码。它可以在旧版本的浏览器或不支持某些新特性的环境中,提供对这些功能的兼容性支持。当新的Web标准或API被引入时,不同的浏览器或环境可能会以不同的速度进行支持和实现。在这种情况下,开发人员可以使用Polyfill来填充这些缺失的功能。
Polyfill通常是一个JavaScript库或脚本,它通过在运行时检测浏览器或环境的功能支持情况,然后根据需要动态地添加缺失的功能或API的实现。例如,如果某个浏览器不支持ES6的新特性,如箭头函数、模板字符串等,开发人员可以使用相应的Polyfill来提供对这些特性的支持。Polyfill会检测浏览器是否支持这些特性,如果不支持,则在运行时添加相应的代码来实现这些特性。
需要注意的是,Polyfill并不是一种通用的解决方案,它可能会增加页面的加载时间和代码体积。因此,在使用Polyfill时,需要根据具体的需求和目标浏览器进行选择和优化。
2、SSE原理
- 客户端通过创建一个EventSource对象来与服务器建立连接。
- 服务器通过发送特定格式的事件流(event stream)数据,将数据推送给客户端。
- 客户端通过监听EventSource对象的事件,如message事件,来接收服务器发送的数据。
- 服务器可以根据需要发送不同类型的事件,如message事件、open事件、error事件等。
3、SSE技术实现:
SSE基于HTTP协议,利用其长连接特性,通过浏览器向服务器发送一个HTTP请求,建立一条持久化连接。
4、SSE应用场景:
- 实时数据大屏(这种不需要客户端做操作的,只需要服务端将数据不断给客户端,并且需要长时间连接,并不一定需要WebSocket)
- chatGPT 返回数据
5、EventSource
EventSource是HTML5中的一个API,用于在客户端与服务器之间建立基于HTTP的单向通信。
二、SSE使用
1、前端
- 创建EventSource对象:
 在客户端的JavaScript代码中,使用new EventSource(url,options)来创建一个EventSource对象.- 其中url是服务器端的URL,必填。
- options是配置项可选参数- Object类型,常用配置包括:- withCredentials:- Boolean类型,标识是否允许发送- Coolie和- HTTP认证信息。默认- false
- headers:- Object类型,标识发送的请求头信息。
- retryInterval:- Number类型,标识与服务器失去连接后,重连时间间隔。默认1000毫秒
 
 
 const sse = new EventSource('http://localhost:3000/api/sse',{
                withCredentials:false,
                headers:{},
                retryInterval: 1000
            })
- 监听事件:
 通过为EventSource对象添加事件监听器,如onmessage、onopen、onerror等,来处理服务器发送的事件。- onmessage:表示已经收到服务端数据。
- onopen:表示已经建立了连接,并开始接收服务端数据。当后端没有定义返回的事件,默认是该事件。
- onerror:表示建立连接或接收数据时发生错误。
 
- 接收事件:
 当服务器发送事件流数据时,EventSource对象会触发相应的事件,客户端可以通过事件监听器来接收和处理这些事件。
 sse.onopen = (e) =>{
                console.log('连接成功', e)
            }
            sse.onmessage = (e) =>{
                console.log('接收到数据', e)
            }
            sse.onerror= (e) =>{
                console.log('发生错误',e)
            }
            sse.addEventListener('message',(e)=>{
                const span = document.getElementById('animate')
                span.remove()
                message.innerHTML += `${e.data}<span id="animate">|</span>`
            })
- 关闭连接:
 如果不再需要与服务器保持连接,可以调用EventSource对象的close()方法来关闭连接。
stop.addEventListener('click',(e)=>{
                console.log('断开连接',e)
                sse.close()
            })
2、后端
后端必须设置响应头 'Content-Type': 'text/event-stream',然后其他就和普通get请求一样。
后端是可以设置事件名称的,返回event 表示定义事件名称
res.write(`event:dg\n`)
3、完整代码
前端
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<style>
    .box{
        height: 100vh;
        width: 100%;
        background: #1B1A22;
    }
    #message{
        color: white;
    }
    #animate{
        display: inline-block;
        padding:0 5px;
        font-size:20px;
        font-weight: bold;
        animation: fade 1s infinite forwards;
    }
    @keyframes fade {
        from{
            opacity: 0;
        }
        to {
            opacity: 1;
        }
    }
</style>
<body>
<div>
    <div class="box">
        <div id="message"><span id="animate">|</span></div>
        <div style="margin-top: 30px"><button id="stop">断开连接</button></div>
    </div>
</div>
</body>
<script>
    const message = document.getElementById('message')
    const stop = document.getElementById('stop')
    document.addEventListener('keydown',(e)=>{
        if (e.keyCode == 13){
            const sse = new EventSource('http://localhost:3000/api/sse',{
                withCredentials:false,
                headers:{},
                retryInterval: 1000
            })
            sse.onopen = (e) =>{
                console.log('连接成功', e)
            }
            sse.onmessage = (e) =>{
                console.log('接收到数据', e)
            }
            sse.onerror= (e) =>{
                console.log('发生错误',e)
            }
            sse.addEventListener('message',(e)=>{
                const span = document.getElementById('animate')
                span.remove()
                message.innerHTML += `${e.data}<span id="animate">|</span>`
            })
            stop.addEventListener('click',(e)=>{
                console.log('断开连接',e)
                sse.close()
            })
        }
    })
</script>
</html>
后端
这里后端用Node
app.get('/api/sse',(req,res)=>{
    res.writeHead(200,{
        'Content-Type': 'text/event-stream',
        'Access-Control-Allow-Origin': '*'
    })
    // 读取本地文件
    const txt =  fs.readFileSync('../SSE/index.txt','utf8')
    // 分割成字符数组
    const arr = txt.split('')
    let currnet = 0
    let timer = setInterval(()=>{
        if (currnet < arr.length){
            // 设置返回事件名称
            // res.write(`event:dg\n`)
            res.write(`data:${arr[currnet]}\n\n`)
            currnet++
        }else{
            clearTimeout(timer)
        }
    },300)
})

注:
 SSE是服务端主动向客户端发送数据,在客户端发送连接数据连接后,客户端就不能再向服务端发送数据了,只能服务端给客户端发送数据,这是因为SSE是单工通讯的。
只接受get请求
服务端没有设置正确的响应头信息,可能导致无法接收数据
总结
总的来说,SSE是一种简单、实时的通信技术,适用于需要实时推送数据的应用场景,提供了一种有效的方式来实现服务器向客户端的实时通信。



















