SSE:用于流式传输的协议

一.什么是SSE

        SSE协议是一种基于http协议的单向通信协议,服务端可以向客户端发送数据,但是客户端不能向服务器发送数据。客户端通过创建一个到服务器的单向连接来监听事件。可以将一次性返回数据包改为流式返回数据。SSE协议支持断线重连,也支持自定义响应事件。比如ChatGpt使用的通信方式就是SSE协议,相比于websocket通信这是一个更为轻量级的通信方式,使用方法简单。但是在浏览器原生的EventSource不支持设置请求头,需要借助第三方包去实现,同时也需要后端设置接口的响应头Content-Type:text/event-stream

二.SSE和WebSocket的区别

        WebSocket  API

           WebSocket是基于TCP协议的一种用于应用层的网络协议,它实现了浏览器与服务器之间的全双工通信,它允许服务器主动发信息给客户端。所以,浏览器和服务器只需要完成一次握手就可以建立持久性的连接,并且能够实现双向数据传输。

        特点:

          1.传输的数据格式可以是文本也可以是二进制形式

          2.不受同源策略的限制,可以与任意服务端进行通信

          3.兼容HTTP协议,默认端口同样是80(ws)和443(ws)

          4.客户端和服务端通信时开销较少,与HTTP协议不同,不需要每次都携带完整的头部信息

          5.若在通信过程中连接中断,需要自己实现断线重连

        区别:

          1.sse协议仅支持服务端向客户端发送数据,而websocket支持双向通信,服务端和客户端之间可以互相通信

          2.sse是一种轻量级的通信协议,而websocket整体的一些方法事件较为复杂

          3.sse支持断线重连机制,而websocket需要自己实现断线重连

          4.sse是基于HTTP协议的通信协议,而websocket是基于TCP协议的网络层通信协议

三.前端使用SSE

 <h1>fetchSSE Demo</h1>
    <button onclick="connectFetch()">建立 fetchSSE 连接</button>
    <button onclick="closeSSE()">断开 fetchSSE 连接</button>
    <br />
    <br />
    <div id="message"></div>
    <script>
        const messageElement = document.getElementById('message')
        let controller = null
        // 建立 FETCH-SSE 连接
        const connectFetch = () => {
            controller = new AbortController()
            fetchEventSource('http://127.0.0.1:3001/fetch-sse', {
                method: 'POST',
                body: JSON.stringify({
                    content: 'xxx'
                }),
                signal: controller.signal,
                onopen: () => {
                    messageElement.innerHTML += `FETCH 连接成功<br />`
                },
                onclose: () => {
                    messageElement.innerHTML += `FETCH 连接关闭<br />`
                },
                onmessage: (event) => {
                    const data = JSON.parse(event)
                    messageElement.innerHTML += `${data.id} --- ${data.time} --- body参数:${JSON.stringify(data.body)}` + '<br />'
                },
                onerror: (e) => {
                    console.log(e)
                }
            })
        }

        // 断开 FETCH-SSE 连接
        const closeSSE = () => {
            if (controller) {
                controller.abort()
                controller = undefined
                messageElement.innerHTML += `FETCH 连接关闭<br />`
            }
        }
        const fetchEventSource = (url, options) => {
            fetch(url, options)
                .then(response => {
                    if (response.status === 200) {
                        options.onopen && options.onopen()
                        return response.body
                    }
                })
                .then(rb => {
                    const reader = rb.getReader()
                    const push = () => {
                        // done 为数据流是否接收完成,boolean
                        // value 为返回数据,Uint8Array
                        return reader.read().then(({ done, value }) => {
                            if (done) {
                                options.onclose && options.onclose()
                                return
                            }
                            options.onmessage && options.onmessage(new TextDecoder().decode(value))
                            // 持续读取流信息
                            return push()
                        })
                    }
                    // 开始读取流信息
                    return push()
                })
                .catch((e) => {
                    options.error && options.error(e)
                })
        }

        

        
        

### Server-Sent Events (SSE) 协议简介 Server-Sent Events(SSE)是一种基于HTTP的轻量级协议,主要用于实现在服务器到客户端之间的单向实时数据推送功能。通过这种机制,服务器可以主动向浏览器发送事件流(Event Stream)。该技术非常适合那些需要实时更新但不涉及大量双向通信的应用场景[^1]。 #### SSE的核心特性 - **单向通信**:SSE仅支持从服务器推送到客户端的数据传输,而不提供反方向的功能。 - **自动重连**:如果连接中断,浏览器能够按照指定的时间间隔尝试重新建立连接。 - **简单易用**:相比WebSocket,SSE更易于实现和维护,因为它依赖于标准的HTTP协议。 - **跨域支持**:可以通过设置`Access-Control-Allow-Origin`头来控制跨域访问权限。 --- ### SSE的使用方法 为了启用SSE,在服务端需配置特定的响应头部以及持续输出的消息体。具体来说: - 响应的内容类型应当被设定为 `text/event-stream`; - 数据以逐行的形式发出,每条消息由关键字开头,比如 `data:` 或者其他合法字段名称如 `id`, `event` 等表示不同的语义信息。 在客户端,则利用原生JavaScript中的`EventSource`对象订阅来自服务器的通知,并处理接收到的信息。 --- ### 实现示例 下面给出一个简单的例子展示如何构建基本的服务端与前端逻辑交互过程。 #### 后端代码片段(Spring Boot框架下) ```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 = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE) public Flux<String> stream() { return Flux.<String>generate(sink -> sink.next("server time:" + LocalDateTime.now())) .delayElements(Duration.ofSeconds(1)); } } ``` 上述代码定义了一个RESTful接口 `/stream` ,它返回的是一个无限序列时间戳字符串给调用方,每隔一秒触发一次新的值生成操作[^2]。 #### 前端HTML页面 ```html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>SSE Example</title> </head> <body> <div id="messages"></div> <script type="text/javascript"> const eventSource = new EventSource('/stream'); eventSource.onmessage = function(event){ const messagesDiv = document.getElementById('messages'); const newMessageDiv = document.createElement('div'); newMessageDiv.textContent = 'Received message: '+ event.data; messagesDiv.appendChild(newMessageDiv); }; // Optional error handling. eventSource.onerror = () => console.error('Error occurred with the connection.'); </script> </body> </html> ``` 此脚本初始化了一个针对路径`/stream`的新`EventSource`实例,每当有新消息到达时都会动态添加至DOM树中显示出来。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值