【AI落地工程技术】-SSE协议

2024-06-13 1324阅读

目录

【AI落地工程技术】-SSE协议
(图片来源网络,侵删)

SSE协议内容

SSE事件格式

使用示例

示例一

客户端(JavaScript)

服务器端(Node.js 示例)

示例二

前端(JavaScript)

后端(Java,使用Spring Boot和Servlet API)


SSE(Server-Sent Events)协议是一种用于服务器主动向客户端推送数据的技术,也称为“事件流”(Event Stream)。它基于HTTP协议,利用长连接特性,在客户端与服务器之间建立一条持久化连接,并通过这条连接实现服务器向客户端的实时数据推送。ChatGPT即采用的是SSE协议。

SSE协议内容

  1. 协议头:
    • SSE协议返回的是事件流,需要指定内容类型。因此,在HTTP header里需要加上以下信息:
      • Content-Type: text/event-stream
      • Connection: keep-alive
      • Cache-Control: no-cache
  2. 协议内容:
    • 协议内容放在HTTP返回的body里,每次返回一个Event信息。
    • 每个Event里可以包含以下5个属性(但并非所有属性都是必需的):
      • id:用于表示Event的序号,客户端通过序号实现断线重连功能。
      • event:表示自定义事件类型,客户端通过该字段区分不同消息。
      • data:表示返回的业务数据,如果数据很长可以分成多行返回。
      • retry:(可选)注释消息,表示重新连接的时间间隔(单位:毫秒)。
    • 每个属性值占用一行,每行的内容都是由属性名称+属性值组成+换行符,之间用冒号隔开(:)。
    • 两个消息之间用额外的换行符(\n\n)区分。

SSE事件格式

每个SSE事件都以文本形式发送,遵循以下格式:

  • 单行注释:以: 开头(例如 : 这是一条注释\n)
  • 字段:由字段名、冒号、字段值以及一个换行符组成(例如 data: This is a message\n)
  • 事件:通过event字段指定(例如 event: myevent\n)
  • ID:通过id字段指定,用于在重新连接时帮助客户端确定错过的消息(例如 id: 123\n)
  • 重试:通过retry字段指定在重新连接之前的延迟时间(单位:毫秒)(例如 retry: 2000\n)
  • 消息结束:两个换行符(\n\n)表示一个事件的结束和下一个事件的开始

    使用示例

    示例一

    客户端(JavaScript)

    // 创建EventSource对象  
    const eventSource = new EventSource('http://example.com/sse');  
      
    // 监听服务器发送的事件  
    eventSource.onmessage = function(event) {  
        console.log('收到消息:', event.data);  
    };  
      
    // 监听服务器关闭连接的事件  
    eventSource.onclose = function() {  
        console.log('连接已关闭');  
    };  
      
    // 监听服务器错误事件  
    eventSource.onerror = function() {  
        console.log('连接出错');  
    };


    服务器端(Node.js 示例)

    const http = require('http');  
      
    const server = http.createServer((req, res) => {  
        if (req.url === '/sse' && req.method === 'GET') {  
            // 设置响应头  
            res.writeHead(200, {  
                'Content-Type': 'text/event-stream',  
                'Connection': 'keep-alive',  
                'Cache-Control': 'no-cache'  
            });  
      
            // 模拟发送数据  
            let count = 0;  
            const interval = setInterval(() => {  
                const eventData = `data: 这是第 ${count++} 条消息\n\n`;  
                res.write(eventData);  
      
                // 假设在发送10条消息后关闭连接  
                if (count > 10) {  
                    clearInterval(interval);  
                    res.end();  
                }  
            }, 1000); // 每秒发送一次  
        }  
    });  
      
    server.listen(8080, () => {  
        console.log('SSE 服务器已启动,监听 8080 端口');  
    });
    在上面的示例中,客户端使用EventSource对象创建一个与服务器端的SSE连接,并监听不同的事件。服务器端则创建一个HTTP服务器,并在接收到特定的GET请求时,通过长连接向客户端发送数据。这个示例模拟了一个简单的SSE服务器,每秒钟向客户端发送一条消息,并在发送了10条消息后关闭连接。
    

    示例二

    前端(JavaScript)

    // 创建EventSource实例并连接到SSE服务  
    var source = new EventSource('/server-sent-events-endpoint');  
      
    // 监听message事件(默认事件类型)  
    source.onmessage = function(event) {  
        console.log('Received data:', event.data);  
    };  
      
    // 监听自定义事件类型  
    source.onmyevent = function(event) {  
        console.log('Received myevent:', event.data);  
    };  
      
    // 监听连接打开事件  
    source.onopen = function(event) {  
        console.log('Connection to server opened.');  
    };  
      
    // 监听连接错误事件  
    source.onerror = function(event) {  
        if (source.readyState === EventSource.CLOSED) {  
            // 连接已关闭,可以尝试重新连接  
            console.log('Connection to server was closed.');  
        }  
    };

    后端(Java,使用Spring Boot和Servlet API)

    在Spring Boot应用中,你可以使用@RestController和@GetMapping来创建一个SSE端点,但更常见的是使用ServletResponse直接发送SSE消息。

    import javax.servlet.ServletException;  
    import javax.servlet.annotation.WebServlet;  
    import javax.servlet.http.HttpServlet;  
    import javax.servlet.http.HttpServletRequest;  
    import javax.servlet.http.HttpServletResponse;  
    import java.io.IOException;  
    import java.io.PrintWriter;  
      
    @WebServlet("/server-sent-events-endpoint")  
    public class SseServlet extends HttpServlet {  
      
        @Override  
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {  
            resp.setContentType("text/event-stream");  
            resp.setCharacterEncoding("UTF-8");  
      
            PrintWriter out = resp.getWriter();  
      
            int count = 0;  
            while (true) { // 模拟持续发送事件  
                out.println("data: Event " + (count++) + " at " + System.currentTimeMillis());  
                out.println("event: server-time"); // 可选的事件类型  
                out.println("retry: 1000\n"); // 推荐客户端在断开连接后等待1秒再重连  
      
                // 刷新输出流  
                out.flush();  
      
                // 暂停一段时间再发送下一条消息  
                try {  
                    Thread.sleep(1000);  
                } catch (InterruptedException e) {  
                    e.printStackTrace();  
                    break;  
                }  
            }  
      
            // 注意:在实际应用中,你可能需要一种机制来优雅地关闭连接,而不是使用无限循环  
        }  
    }

    在这个示例中,我们创建了一个Servlet来模拟SSE服务。Servlet响应设置了正确的内容类型和字符编码,并使用PrintWriter发送SSE事件。在实际应用中,你可能会使用一个更复杂的逻辑来控制何时发送消息以及如何优雅

VPS购买请点击我

免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们,邮箱:ciyunidc@ciyunshuju.com。本站只作为美观性配图使用,无任何非法侵犯第三方意图,一切解释权归图片著作权方,本站不承担任何责任。如有恶意碰瓷者,必当奉陪到底严惩不贷!

目录[+]