SSE – Server Sent Events – 服务端主动推送

2022-11-22 18:52:56 浏览数 (1)

本页目录

  • SSE介绍
  • SSE的数据格式
  • SpringBoot接入SSE
    • 前端代码
    • 后端代码
    • 测试

SSE介绍

SSE则是部署在 HTTP协议之上的,现有的服务器软件都支持此协议。

SSE是一个轻量级协议,相对简单;WebSocket是一种较重的协议,相对复杂。但SSE只支持单向交互(服务器给客户发送),Websocket支持双向交互。

SSE默认支持断线重连,WebSocket则需要额外部署。

数据格式方面, SSE 使用的是 UTF8 编码的文本格式。

SSE的HTTP response 里header Content-Type 的值是 text/event-stream。不可变!

SSE的数据格式

每个SSE的消息响应分为4个元素:

  • retry:重试时间,单位毫秒,只能为数字(SSE请求失败,就会发送新的请求)
  • id:消息ID(自定义)
  • event:时间类型(自定义)
  • data:消息的内容(自定义)

下图是4个消息,注意,多个消息之间中间会有个空行(nn)。单个消息之间元素间隔是换行n

代码语言:javascript复制
retry: 5000
id: 1cd7bb64-4341-4f5d-a690-4298b8a8ae20
event: eventType
data: Sun Nov 20 18:23:11 CST 2022

retry: 5000
id: 2f57295d-3eaa-4e5c-a787-55fff58d9b05
event: eventType
data: Sun Nov 20 18:23:12 CST 2022

retry: 5000
id: 6a9618de-99e7-4c03-91f8-dcdd7601a8d0
event: eventType
data: Sun Nov 20 18:23:13 CST 2022

retry: 5000
id: c5fdcc90-b1f7-4058-9a3a-d63881ffea8b
event: eventType
data: Sun Nov 20 18:23:14 CST 2022

SpringBoot接入SSE

不依赖于任何Jar包,本质只是一个Http协议,然后指定ContentType,然后返回相应的格式!

前端代码

代码语言:javascript复制
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>SSE链接测试</title>
</head>
<body>
消息类型是message消息:
<div id="ssediv">默认消息</div>
<br>
消息类型是diyEventType消息:
<div id="diyssediv">DIY SSE消息</div>
</body>
<script>
    var sse = new EventSource("http://localhost:8081/sse");

    /**
     * 默认是没有指定eventTtpe的消息,但eventType就为message。
     * 等价于addEventListener("message" ...
     */
    sse.onmessage = function (ev) {
        console.error("这里只能处理eventType为message的消息")
        var elementById = document.getElementById("ssediv");
        elementById.innerHTML = ev.data;
    }

    /**
     * 添加指定类型消息处理,eventType是后台自定义的
     */
     sse.addEventListener("diyEventType",event => {
         console.error("自定义事件" event.data)
         var elementById2 = document.getElementById("diyssediv");
         elementById2.innerHTML = event.data;
     })

    /**
     * SSE连接异常
     */
    sse.onerror = function (){
        alert("服务器已停止!")
    }

    /**
     * SSE连接成功
     */
    sse.onopen = function (){
        alert("服务器已连接!")
    }

    // 不要忘记关闭断开连接哦
    // sse.close()
</script>
</html>

后端代码

代码语言:javascript复制
@Controller
public class SSE {

    @GetMapping(value = "/sse")
    @ResponseBody
    public String getMessage(HttpServletResponse response) {
        // System.out.println("请求进入了");
        response.setContentType("text/event-stream");   // 指定ContentType,不可变
        response.setCharacterEncoding("utf-8");         // 指定响应字符集,是否可变,没测试,但建议指定utf-8
        while (true) {
            String s = "";
            s  = "retry: 5000n";                   // 客户端没有获取到数据,就不断发送新的请求(间隔5秒),直到有数据。
            s  = "id: "   UUID.randomUUID()   "n"; // 这里指定消息ID
            s  = "event: eventTypen";              // 这里定义事件类型,自定义!
            s  = "data: "   new Date()   "nn";    // 这里设置返回的数据
            try {
                PrintWriter pw = response.getWriter();
                Thread.sleep(1000L);
                pw.write(s);
                pw.flush();
            } catch (IOException e) {
                throw new RuntimeException(e);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

测试

注意避免跨域,浏览器URL用localhost,前端SSE的URl不能是127.0.0.1。

如果Jmeter直接打到请求上,200个连接,直接导致任何请求无法进行。停止Jmeter后,依旧无法进行请求。lsof -i:服务端口,都是closed也无法

特殊说明: 以上文章,均是我实际操作,写出来的笔记资料,不会盗用别人文章!烦请各位,请勿直接盗用!转载记得标注来源!

0 人点赞