使用tornado实现sse

news/2024/10/17 21:22:47/

sse

SSE(Server-Sent Events,服务器推送事件)是一种用于在服务器和客户端之间建立单向持久连接,允许服务器实时向客户端推送数据的网络通信协议。SSE是基于HTTP协议的,它允许服务器不断地将事件消息发送到客户端浏览器,以便在不刷新页面的情况下更新网页内容。

SSE(Server-Sent Events,服务器发送事件)协议具有以下主要特点:

  1. 单向通信: SSE是一种单向通信协议,数据是从服务器向客户端推送的。客户端无法通过同一连接向服务器发送请求,只能被动接收来自服务器的数据。

  2. 基于HTTP: SSE建立在HTTP协议之上,使用标准的HTTP连接。它不需要特殊的端口或协议,可以与现有的Web服务器和基础设施无缝集成。

  3. 文本格式: SSE使用纯文本格式传输数据,通常采用UTF-8编码。这意味着数据在传输过程中是可读的,易于解析和处理,无需复杂的二进制编码/解码。

  4. 事件模型: 数据通过事件模型进行组织,每个事件由一个事件类型(event)和事件数据(data)组成。服务器可以发送不同类型的事件,并将相关数据传输给客户端。这有助于客户端根据事件类型来处理数据。

  5. 自动重连: SSE支持自动重连功能。如果连接断开,客户端会自动尝试重新连接服务器,以保持与服务器的连接。这有助于提高连接的稳定性和可用性。

  6. 长连接: SSE建立长连接,而不是短连接。这意味着连接在事件之间保持打开状态,而不会在每次事件传输后关闭。长连接可以减少连接建立和断开的开销,有助于实现实时数据传输。

  7. 浏览器支持: SSE协议广泛受到现代Web浏览器的支持,包括Chrome、Firefox、Safari等。这意味着无需额外的插件或库,SSE可以在Web应用程序中轻松使用。

总的来说,SSE是一种简单而有效的协议,用于实现基于HTTP的服务器到客户端的实时数据推送。它的特点包括易于部署、适用于多种浏览器、支持自动重连和长连接,以及采用文本格式传输数据等,使其成为实时Web应用程序的有力工具。

简单的代码示例

import tornado.web
import tornado.ioloopclass SSEHandler(tornado.web.RequestHandler):def initialize(self):# 设置响应头,告诉浏览器这是SSE流self.set_header('Content-Type', 'text/event-stream')self.set_header('Cache-Control', 'no-cache')self.set_header('Connection', 'keep-alive')def send_event(self, event, data):# 发送SSE事件消息message = f"event: {event}\ndata: {data}\n\n"self.write(message)self.flush()def get(self):        # 模拟数据,您可以替换成您的实际数据源for i in range(1, 6):data = {"message": "Hello, World!"}# 发送JSON数据作为SSE事件消息self.send_event("update", json.dumps(data))if __name__ == "__main__":app = tornado.web.Application([(r"/sse", SSEHandler)])app.listen(8888)tornado.ioloop.IOLoop.current().start()

设置请求头

self.set_header(‘Content-Type’, ‘text/event-stream’)
设置响应的Content-Type为’text/event-stream’非常重要,因为这是SSE协议的一部分,它告诉浏览器响应的内容是一个SSE流,而不是普通的文本或HTML页面。这样浏览器就能够正确地处理这个响应,并将其解析为事件流。

SSE是一种服务器向客户端推送数据的协议,通常用于实时更新网页内容,比如实时聊天应用程序或实时更新的信息源。SSE协议定义了一种特殊的文本格式,其中包含一系列事件消息,每个消息之间用特定的格式分隔。这些事件消息可以包含各种信息,如文本、JSON数据等。

设置Content-Type为’text/event-stream’有以下作用:

  1. 告知浏览器响应的内容类型:浏览器会根据Content-Type来确定如何处理响应内容。设置为’text/event-stream’告诉浏览器,这个响应是一个SSE流,需要按照SSE协议规范进行处理。

  2. 启用浏览器的SSE处理机制:浏览器在接收到Content-Type为’text/event-stream’的响应后,会自动启动SSE处理机制,开始监听来自服务器的事件消息。

  3. 正确解析事件消息:SSE协议要求事件消息以特定的格式发送,包括事件标识符、数据字段等。浏览器会根据Content-Type为’text/event-stream’来解析这些事件消息,确保正确地提取事件数据并将其展示在网页上。

self.set_header(‘Cache-Control’, ‘no-cache’)
设置Cache-Control为no-cache的HTTP响应头是为了确保浏览器不会缓存SSE响应。这是因为SSE是一种持续性连接,它不应该被浏览器缓存,否则可能导致不可预测的问题。

下面是关于为什么需要设置Cache-Control为no-cache的一些具体原因:

  1. 避免缓存数据: SSE协议的核心目标是实时将数据从服务器推送到客户端,而不是获取缓存的数据。如果不设置Cache-Control为no-cache,浏览器可能会缓存SSE响应,导致客户端只接收到一次性的数据更新,而后续的更新被缓存并未实时显示。

  2. 保持连接活动: SSE建立的是长连接,浏览器需要保持与服务器的持久连接以接收来自服务器的事件消息。如果响应被缓存,浏览器可能会认为连接已完成,而不再接收后续的事件消息。

  3. 避免数据过期: SSE通常用于实时或流式数据,这些数据可能会频繁更新。如果浏览器缓存了旧数据,用户将无法看到最新的信息。

通过设置Cache-Control为no-cache,您告诉浏览器不要缓存这个响应,而是要始终从服务器获取最新的事件消息。这有助于确保SSE的实时性和准确性。

self.set_header(‘Connection’, ‘keep-alive’)
设置self.set_header(‘Connection’, ‘keep-alive’)是为了确保HTTP连接保持活跃,允许服务器持续地向客户端发送事件消息,而不会在每次消息之后关闭连接。这是SSE协议的核心要求之一,因为SSE旨在支持长连接,以实时地将数据从服务器推送到客户端。

下面是为什么需要设置Connection头为keep-alive的一些原因:

  1. 长连接支持: SSE依赖于长连接,这意味着客户端需要与服务器建立一个持久的连接,以便服务器可以随时向客户端推送事件消息。Connection头设置为keep-alive告诉服务器和客户端保持连接的状态,而不是在每次响应后立即关闭连接。

  2. 降低延迟: 如果连接在每个消息后关闭,客户端将不得不重新建立连接,这会引入额外的网络延迟。通过保持连接活跃,可以避免不必要的连接建立和断开,提高实时性。

  3. 减少资源开销: 在HTTP/1.1中,keep-alive连接是默认行为,但在某些情况下服务器和客户端可能会选择关闭连接以节省资源。然而,在SSE的上下文中,这是不合适的,因为SSE需要保持连接以持续传输事件消息。

在Tornado中,您可以在SSE请求处理程序中使用self.set_header(‘Connection’, ‘keep-alive’)来设置Connection头,以确保连接保持活跃。

数据返回

在Tornado中,self.write()和self.flush()都用于在HTTP响应中发送数据,但它们在作用和用法上有一些不同。

  1. self.write()的作用:

    self.write()方法用于将数据写入HTTP响应缓冲区,但不立即发送到客户端。它将数据添加到响应中,并等待进一步的处理。
    每次调用self.write()都会将数据追加到响应缓冲区中,而不是替换前面的数据。
    self.write()通常用于多次写入响应,以便将多个数据块组合成一个响应。

  2. self.flush()的作用:

    self.flush()方法用于立即发送缓冲区中的数据到客户端,而不等待响应完成。它可以用于确保数据尽快传送到客户端,而不需要等待整个响应完成后才发送。
    通常在使用长连接(如SSE)时,self.flush()非常有用,因为它允许您即时地将数据推送给客户端,而不需要等待缓冲区填满或响应完全构建。

对于SSE实现,通常在每次向前端推送事件消息时,建议使用self.flush(),以确保数据立即传送到客户端,而不需要等待缓冲区填充。这样可以实现实时性,使事件消息能够尽快到达客户端。


http://www.ppmy.cn/news/1103828.html

相关文章

Redis事务机制

Redis 是一款开源的、内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。在日常的使用中,我们经常会遇到需要一次执行多个命令,并且这些命令要么全部成功,要么全部失败的场景。这就需要用到 Redis 的事务机制。 Redi…

【驱动开发】实现三盏灯的控制,编写应用程序测试

head.h #ifndef __HEAD_H__ #define __HEAD_H__//LED1:PE10 //LED2:PF10 //LED3:PE8#define LED_RCC 0X50000A28 //使能GPIO#define LED_MODER 0X50006000 //设置输出模式 #define LED_ODR 0X50006014 //设置输出高低电平#define LED2_MODER 0X50007000 …

粉底液、口红、睫毛膏,眼膜等护肤品和彩妆上架亚马逊需要做什么认证?HRIPT/RIPT测试,斑贴测试,COA认证和BCOP认证办理

亚马逊要求化妆、美容类睫毛膏、眼膜、足贴、假睫毛、洗发水、美甲套装等HRIPT / RIPTCOA测试,如果是眼睛这个部位使用的话 还需要出示BCOP认证 为了确保在使用产品或原料后不会产生潜在的刺激或过敏。亚马逊要求化妆品,美容产品,指甲胶等需…

Vue 组件中如何引入外部的js文件

Vue 组件中如何引入外部的js文件 背景 在Vue中,通常我们引入一个js插件都是使用npm 方式下载然后import使用的。但是我现在本地有了js文件或者是一个远程js文件链接,我不想使用npm install xxx 的方式,有什么办法吗? 方式一 简…

抖音小程序开发教学系列(5)- 抖音小程序数据交互

第五章:抖音小程序数据交互 5.1 抖音小程序的网络请求5.1.1 抖音小程序的网络请求方式和API介绍5.1.2 抖音小程序的数据请求示例和错误处理方法 5.2 抖音小程序的数据缓存和本地存储5.2.1 抖音小程序的数据缓存机制和使用方法5.2.2 抖音小程序的本地存储和数据持久化…

【深度学习】 Python 和 NumPy 系列教程(七):Python函数

目录 一、前言 二、实验环境 三、Python函数基础 1. 定义函数 2. 参数传递 3. 函数调用 4. 返回值 5. 函数文档字符串 四、将函数存储在模块中 1. 创建模块 2. 导入模块 a. import 模块名 b. from 模块名 import 函数名 c. from 模块名 import * 五、多种形式的…

多语言开发(vant

参考:https://blog.csdn.net/qq_44649801/article/details/131878128?spm1001.2014.3001.5506 一、抛出字段对象A export default { } 二、引入汇总文件,(主要的是 模块分割 汇总,对A 等的处理 export default { A,B,…

微信小程序云开发数据懒加载+打破云数据库返回数据条数限制

目录 数据懒加载 打破数据表返回条数限制 数据懒加载 show.wxml <view wx:for="{{Adata}}" wx:key="index" style="padding: 80rpx 10rpx 140rpx;border-bottom: rgb(109, 134, 134) 2px solid;"><view style="margin-left: 20…