前后端分离项目实现SSE

news2024/11/18 17:35:27

SSE介绍

在日常web开发中经常会遇到查看数据最新状态的业务场景,例如查看任务状态与日志内容等。比较场景的解决方案是轮循和SSE。

Server-Sent Events (SSE) 是一种允许服务器通过单向通道向客户端推送更新的技术。它基于HTTP协议,客户端使用一个标准的HTTP请求来连接到服务器,并保持这个连接打开,服务器可以在这个连接上持续地发送数据。

SSE的工作原理

  1. 客户端通过HTTP请求连接到服务器,并保持连接不断开。
  2. 服务器推送text/event-stream类型的数据给客户端。
  3. 客户端监听服务器发送的消息,并进行处理。

SSE对比WebSocket

通信方式

  • SSE 是单向的,服务器向客户端推送消息,客户端不能主动向服务器发送数据。
  • WebSocket 是双向的,允许客户端和服务器之间的双向通信。

协议

  • SSE基于HTTP协议,使用HTTP/1.1HTTP/2,更适合需要基于现有HTTP/HTTPS基础设施的应用。
  • WebSocket 是独立协议,虽然也从HTTP握手开始,但连接升级为WebSocket协议后不再使用HTTP,适合需要低延迟、双向通信的应用。

重连与状态管理

  • SSE内置自动重连机制,如果连接断开,客户端会自动尝试重新连接。
  • WebSocket需要额外的代码来处理断开后的重连机制。

SSE对比HTTP轮询

通信效率

  • HTTP轮询客户端周期性地发送请求以检查服务器是否有新数据,这种方法在没有新数据时会产生大量无效请求,浪费带宽和资源。
  • SSE可以保持一个持久连接,只在有新数据时推送消息,效率更高。

实时性

  • HTTP轮询由于间隔请求,通常会有较大的延迟。
  • SSE提供准实时的推送服务,延迟较小。

SSE的优势

  • 简单实现: SSE是基于HTTP的标准,使用方便,客户端只需通过标准的JavaScript API就可以处理消息推送。
  • 自动重连: SSE内置自动重连机制,开发者不需要额外编写代码来处理连接丢失问题。
  • 消息订阅: SSE支持事件流的多类型消息订阅,客户端可以根据不同的事件类型处理不同的数据。
  • 高兼容性: SSE使用HTTP协议,兼容性好,适用于各种网络环境。

SSE的局限性

  • 单向通信: 只能从服务器推送消息到客户端,不能实现双向通信。如果需要双向通信,WebSocket更为合适。
  • 浏览器兼容性: 虽然现代浏览器都支持SSE,但某些旧版本浏览器可能需要使用Polyfill等兼容解决方案。
  • 消息丢失: 如果连接断开且未能自动重连,有可能会丢失未接收到的消息。

适用场景

SSE非常适合需要从服务器向客户端推送实时更新的应用场景,例如:

  • 实时数据更新(例如新闻、股票行情)
  • 服务器事件通知
  • 轻量级的实时通信应用

在需要简单、可靠的服务器推送方案且无需双向通信的场景下,SSE是一个不错的选择。如果需要更复杂的通信机制,WebSocket可能更为合适。

Django后端SSE

创建sse应用

首先创建一个新的APP来实现SSE的功能。

python manage.py startapp sse

在settings.py的INSTALLED_APPS中添加新的APP。

INSTALLED_APPS = [
    ...,
    "sse",
]

创建路由

接下来修改根路由,新增sse前缀的子路由配置,并在APP目录中,新建一个urls.py文件来处理指向这个应用的请求。

  • DRF/urls.py
from django.contrib import admin
from django.urls import path, include, re_path
from django.views.static import serve
from api import views
from django.conf import settings
urlpatterns = [
    ……
    # SSE
    path('v1/sse/', include('sse.urls', namespace='sse'))
]
  • sse/urls.py
from rest_framework import routers
from sse import views
from django.urls import path

app_name = "sse"
urlpatterns = [
    # SSE
    path('demo/', views.DemoAPIView.as_view())
]
router = routers.DefaultRouter()
urlpatterns += router.urls

创建视图函数

创建APIView视图,模拟后端实时触发消息通知。需要注意的是后端发送符合SSE协议的消息必须满足以下要求:

  1. 消息格式正确。SSE 要求每个消息必须以 data: 开头,且后面有一个换行符分隔。例如:
data: This is a message

data: {"message": "This is a message"}
  1. 响应内容类型设置:服务器响应的 Content-Type 必须设置为 text/event-stream,否则浏览器和客户端会将其视为普通的 HTTP 响应。
  2. 后端跨域配置:如果你的请求是跨域的,确保后端 CORS 配置允许 EventSource 的跨域请求,具体可参考文档:跨域访问-崔亮的博客 (cuiliangblog.cn)

通常情况下我们都会用异步实现SSE,所以生成器event_stream()也得是异步的。如果我们需要处理长时间的任务,那么可以写一个异步函数并通过yield返回状态。

  • sse/views.py
import asyncio
import random
import time
from django.http import StreamingHttpResponse
from loguru import logger
from rest_framework.views import APIView


class DemoAPIView(APIView):
    """
    SSE示例数据
    """

    @staticmethod
    def get(request):
        # 定义一个生成器,持续输出数据流
        async def event_stream():
            while True:
                value = random.randint(0, 5)
                await asyncio.sleep(value)  # 模拟随机延时
                msg = 'data: {{"message": "now time:{0} value:{1}"}}\n\n'.format(time.strftime('%Y-%m-%d %H:%M:%S'), value)
                yield msg
        # 返回 StreamingHttpResponse,Content-Type 设置为 text/event-stream
        response = StreamingHttpResponse(event_stream(), content_type='text/event-stream',
                                         headers={'Cache-Control': 'no-cache', 'Connection': 'keep-alive'})
        return response

启动服务

为了让项目异步运行,我们需要使用ASGI来启动项目,ASGI配置可参考文档:Django新特性汇总-崔亮的博客 (cuiliangblog.cn)。

uvicorn DRF.asgi:application --reload

访问验证

接下来使用浏览器访问api接口地址,浏览器会持续不断的接收响应类型为text/event-stream的最新实时数据并打印。

Nginx中间件SSE

为了保证SSE实时推送,需要对Nginx配置确保禁用缓冲区并确保Nginx不会中断SSE流,确保Nginx可以正确处理SSE连接。

基础反向代理配置

首先配置一个基础的Nginx反向代理,用于反向代理Django应用。

server {
    listen 80;
    server_name ~^.*$;

    location / {
        proxy_pass http://drf:8000;
        proxy_set_header Host $host;
  	    proxy_set_header X-Real-IP $remote_addr;
  	    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

为SSE配置特定的location

为了让Nginx正确处理SSE,需要禁用Nginx的响应缓冲区,并启用HTTP/1.1协议支持(SSE依赖此协议的持续连接功能)。

server {
    listen 80;
    server_name ~^.*$;

    location /v1/sse/ {
        # 代理到Django应用
        proxy_pass http://drf:8000;
        # 禁用响应缓冲,确保数据流立即发送到客户端
        proxy_buffering off;
        # 允许Nginx处理的最大响应头的大小(防止头部被缓存)
        proxy_cache_bypass $http_upgrade;
        # HTTP/1.1 协议支持,防止默认使用HTTP/1.0
        proxy_http_version 1.1;
        # 防止Nginx在长连接时设置 "Connection: close"
        proxy_set_header Connection '';
        # 设置请求头
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    location / {
        # 其他反向代理配置
        ……
    }
}

通过这个配置,Nginx可以正确处理和代理Django Rest Framework中的SSE流,并且不会因为默认的缓冲机制导致SSE数据延迟。这样,前端Vue.js应用就可以实时接收来自后端的SSE推送消息。

VUE前端SSE

前端实现SSE可以使用浏览器的原生API——EventSource来实现。但是EventSource并不支持直接设置自定义的 HTTP 请求头,如 Accept 或 Authorization。如果使用需要自定义请求头,推荐使用 @microsoft/fetch-event-source。

这个库基于 Fetch API 实现,提供了比原生 EventSource 更灵活的控制,可以自定义 headers 和其他配置。并内置了自动重连机制,可以轻松地实现高级的错误处理逻辑。如果连接断开,浏览器会自动重试。

仓库地址:Azure/fetch-event-source: A better API for making Event Source requests, with all the features of fetch() (github.com)

封装请求函数

  • src/api/home.js
// 获取SSE数据
export function getSSE()  {
  return import.meta.env.VITE_APP_BASE_URL + '/sse/demo/'
}

配置路由

  • src/router/index.js
import {createRouter, createWebHistory} from 'vue-router';

const router = createRouter({
    history: createWebHistory(),  //h5模式createWebHistory
    routes: [
       ……
        {
            path: '/test',
            component: () => import('@/views/Test.vue'),
            meta: {
                title: '测试',
            }
        }
    ]
})
// 路由导航守卫
router.beforeEach((to, from, next) => {
    document.title = to.meta.title
    next()
})
export default router;

创建测试页

在 @microsoft/fetch-event-source 中,主要使用 fetchEventSource 函数来创建一个新的 EventSource 连接。这个函数接受一个 URL 参数,以及一个配置对象,其中可以包含一些选项,如请求方法、请求头、请求体等。当服务器向客户端推送事件时,可以通过 onmessage 回调函数来处理这些事件。此外,还可以提供 onerror 和 onclose 回调函数来处理连接错误和关闭事件。

  • src/views/Test.vue
<template>
  <h1>这是测试页</h1>
  <p v-for="item in data">
    {{ item.message }}
  </p>
</template>

<script setup>
import {ref, onMounted, onUnmounted} from "vue";
import {fetchEventSource} from '@microsoft/fetch-event-source';
import {getSSE} from "@/api/home";

const data = ref([])
const connectSSE = async () => {
  const url = getSSE()
  console.log(url)
  await fetchEventSource(url, {
    method: 'GET',
    headers: {
      'Accept': '*/*'
    },
    onmessage: async (event) => {
      console.log(event)
      console.log(JSON.parse(event.data))
      data.value.push(JSON.parse(event.data))
    },
    onerror(err) {
      console.error('Error:', err);
      if (err.status === 500) {
        // 服务器错误时重新连接
        setTimeout(() => connectSSE(), 5000);
      }
    },
    onopen(response) {
      if (response.ok) {
        console.log('Connection start');
      }
    },
    onclose() {
      console.log('Connection close');
    }
  })
}
onMounted(() => {
  connectSSE();
});
onUnmounted(() => {

});


</script>

<style scoped lang="scss">

</style>

访问验证

接下来访问vue测试页面路由,查看控制台信息验证,可以持续打印最新的数据流内容。

查看更多

微信公众号

微信公众号同步更新,欢迎关注微信公众号《崔亮的博客》第一时间获取最近文章。

博客网站

崔亮的博客-专注devops自动化运维,传播优秀it运维技术文章。更多原创运维开发相关文章,欢迎访问https://www.cuiliangblog.cn

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2132951.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2024CCPC网络预选赛

vp链接&#xff1a;Dashboard - The 2024 CCPC Online Contest - Codeforces B. 军训 II 序列 a 从小到大排列或者从大到小排列时&#xff0c;不整齐度是最小的。方案数是所有相同数字的个数的排列数的乘积。如果首尾的数字不同的话&#xff0c;还要再乘个 2。 #include <…

Running setup.py install for wxPython did not run successfully.

Running setup.py install for wxPython did not run successfully. 欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 欢迎来到我的主页&#xff0c;我是博主英杰&#xff0c;211科班出身&#xff0c;就职于医疗科技公司&#xff0c;热衷分享知识&#xff0c;武汉城市开…

axure循环介绍

一直在犹豫要不要写关于axure循环方面的介绍&#xff0c;因为循环的场景用其它方法都是可以实现的&#xff0c;今天还是用上次手机号码判断的案例来写一下循坏吧。 1、页面新建元件&#xff0c;手机号码输入框重命名为【手机号码输入框】按钮重命名为【按钮】再在页面拖动上来一…

python学习第八节:爬虫的初级理解

python学习第八节&#xff1a;爬虫的初级理解 爬虫说明&#xff1a;爬虫准备工作&#xff1a;分析网站url分析网页内容 爬虫获取数据&#xff1a;1.使用urllib库发起一个get请求2.使用urllib库发起一个post请求3.网页超时处理4.简单反爬虫绕过5.获取响应参数6.完整请求代码 解析…

【Python机器学习】长短期记忆网络(LSTM)

目录 随时间反向传播 实践 模型的使用 脏数据 “未知”词条的处理 字符级建模&#xff08;英文&#xff09; 生成聊天文章 进一步生成文本 文本生成的问题&#xff1a;内容不受控 其他记忆机制 更深的网络 尽管在序列数据中&#xff0c;循环神经网络为对各种语言关系…

Java项目: 基于SpringBoot+mybatis+maven医院管理系统(含源码+数据库+任务书+开题报告+毕业论文)

一、项目简介 本项目是一套基于SpringBootmybatismaven医院管理系统 包含&#xff1a;项目源码、数据库脚本等&#xff0c;该项目附带全部源码可作为毕设使用。 项目都经过严格调试&#xff0c;eclipse或者idea 确保可以运行&#xff01; 该系统功能完善、界面美观、操作简单、…

强化网络安全:通过802.1X协议保障远程接入设备安全认证

随着远程办公和移动设备的普及&#xff0c;企业网络面临着前所未有的安全挑战。为了确保网络的安全性&#xff0c;同时提供无缝的用户体验&#xff0c;我们的 ASP 身份认证平台引入了先进的 802.1X 认证协议&#xff0c;确保只有经过认证的设备才能接入您的网络。本文档将详细介…

【我的 PWN 学习手札】Fastbin Attack

关于fastbin&#xff0c;有很多攻击利用手法&#xff0c;本篇只是讲述了修改fd指针&#xff0c;分配到fake_chunk&#xff0c;更多利用手法拆分到后面的博客中 目录 前言 一、Fastbin保护检查机制 二、利用手法 &#xff08;1&#xff09;分配到任意地址&#xff08;__mall…

VScode相关问题与解决

1.写c文件时找不到头文件stdio.h 在linux下我们gcc命令来编译c文件时&#xff0c;会遇到找不到头文件的问题 解决方法&#xff1a;我们每写完一个文件记得保存一下文件即可&#xff0c;这样就解决了找不到头文件的问题&#xff01; 参考链接&#xff1a; /usr/bin/ld: /us…

Java实现生成验证码实战

文章目录 需求描述思想思路实现代码实现效果 在实际项目中&#xff0c;管理端的登录&#xff0c;会涉及验证码的校验&#xff0c;简单的数字与字母组合形式&#xff0c;在Java中要如何生成与实现&#xff0c;记录下来&#xff0c;方便备查。 需求描述 生成8位的由数字、大写字…

总结拓展九:SAP数据迁移(2)

第三节 数据迁移工具LTMC实操 1、供应商&#xff08;BP&#xff09;主数据导入 1.1 首先在SAP S 4系统&#xff0c;通过事务代码“LTMC”跳转进入数据迁移控制台&#xff08;网页版&#xff09;&#xff1b; 1.2 点击“创建”按钮&#xff0c;创建迁移项目“NJDHMM-01”; 传…

AI问答-Vue实例属性/实例方法:$refs、$emit、$attrs、$props、$data...

一、本文简介 在Vue.js中&#xff0c;$ 符号通常用于表示Vue实例或组件上的内置属性和方法&#xff0c;这些被称为“实例属性”或“实例方法”。以下是一些常见的以$开头的Vue实例属性和方法 1.1、实例属性 序号实例属性解释1$dataVue实例的数据对象&#xff0c;用于存储组件…

Java铸基之路:运算符的深入学习!(上)

&#x1f51d;&#x1f51d;&#x1f51d;&#x1f51d;&#x1f51d;&#x1f51d;&#x1f51d;&#x1f51d;&#x1f51d;&#x1f51d;&#x1f51d;&#x1f51d;&#x1f51d;&#x1f51d;&#x1f51d; &#x1f947;博主昵称&#xff1a;小菜元 &#x1f35f;博客主页…

【HarmonyOS NEXT开发】如何设置水平/垂直方向的左/居中/右对齐——RelativeContainer的AlignRules设置

文章目录 【HarmonyOS NEXT开发】如何设置水平/垂直方向的左/居中/右对齐——RelativeContainer的AlignRules设置RelativeContainer 和 AlignRules 的关系AlignRules 语法详解 【HarmonyOS NEXT开发】如何设置水平/垂直方向的左/居中/右对齐——RelativeContainer的AlignRules设…

RK3588九鼎创展方案在Arm集群服务器的项目中的应用分析​​

RK3588九鼎创展核心板&#xff0c;搭载8核瑞芯微3588芯片&#xff0c;具备高性能、低功耗以及强大的多媒体和AI处理能力。在Arm集群服务器项目中&#xff0c;RK3588系列芯片用有明显的性能优势。本文将结合RK3588芯片的性能特征以及九鼎创展的项目经验来分析RK3588在集群服务器…

编写XBOX控制器实现鼠标键盘输入

1.核心部分, XINPUT输入封装 XInput封装https://mp.csdn.net/mp_blog/creation/editor/1420701282.对话框窗口编写 Win32 对话框封装-CSDN博客https://blog.csdn.net/Flame_Cyclone/article/details/142110008?spm1001.2014.3001.5501 3.使用到的其他封装 字符串编码转换与…

惊人转变!从信息奴隶到思考大师,你只需掌握这几点专注力提升法!

引言 信息超载时代的今天&#xff0c;人们的主要问题不再是获取信息的资源渠道不足&#xff0c;任何一个信息&#xff0c;都可以通过一篇文章&#xff0c;一个视频来找到对应的相关信息&#xff0c;无极生太极、太极生两仪、两仪生四象。任何一个信息源中&#xff0c;都包含着…

设计模式-行为型模式-备忘录模式

1.备忘录模式定义 在不破坏封装的前提下&#xff0c;捕获一个对象的内部状态&#xff0c;并在该对象之外保存这个状态&#xff0c;这样可以在以后将对象恢复到原先保存的状态&#xff1b; 1.1 备忘录模式的优缺点 优点 提供了一种状态恢复的实现机制&#xff0c;使得用户可以…

社区营销:如何通过聚集人群提升品牌

“没有人是孤岛”&#xff0c;约翰多恩这样写道。如果可以&#xff0c;请忽略他的性别偏见。他写这句话是在1624年&#xff08;那时候真的不一样&#xff09;。尽管如此&#xff0c;几个世纪后&#xff0c;他的话依然铿锵有力&#xff1a;很少有人能够在孤独中茁壮成长。我们是…

Maven从入门到精通(二)

一、什么是pom.xml pom.xml是Maven项目的核心配置文件&#xff0c;它是 项目对象模型 - Project Object Model&#xff08;POM&#xff09;的缩写。POM定义了项目的所有属性&#xff0c;包括项目的名称、版本、依赖关系、构建配置等。使用pom.xml&#xff0c;我们可以轻松地管…