使用Server-Sent Events实现后端主动向前端进行通信

目录

概述

使用 Server-Sent Events (SSE)

示例

1.创建SpringBoot项目添加web依赖,并编写以下代码

2.创建Vue项目并在项目的.vue文件中编写以下代码

效果说明

使用触发的方式向前端传递数据

总结


概述

在典型的前后端分离架构中,前端通过发起 HTTP 请求(例如使用 Axios 或 Fetch API)向后端发送请求,后端处理这些请求并返回响应。这种模式是常见的,并符合常规的网络通信方式。

然而,有时候确实存在一些特殊情况或需求,需要后端通过主动推送的方式与前端进行通信。这通常使用 WebSocket 或 Server-Sent Events (SSE) 技术来实现。WebSocket 通常更适合实时双向通信,而 SSE 更适合单向通知。本文主要使用 Server-Sent Events 实现。

使用 Server-Sent Events (SSE)

Server-Sent Events (SSE) 允许服务器单向推送事件到浏览器。在 Spring Boot 中,使用 SseEmitterResponseBodyEmitter 类来实现 SSE。

示例

1.创建SpringBoot项目添加web依赖,并编写以下代码

创建SseController类,用于传递数据

import com.hgkx.pojo.MyData;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;import java.io.IOException;@RestController
@RequestMapping("/sse")
public class SseController {private SseEmitter emitter;@GetMapping("/events")public SseEmitter streamEvents() throws IOException {SseEmitter emitter = new SseEmitter();emitter.send("向前端传递的数据");return emitter;}
}

创建GlobalCorsConfig配置类用于解决前后端跨域问题

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;@Configuration
public class GlobalCorsConfig {@Beanpublic CorsFilter corsFilter() {CorsConfiguration config = new CorsConfiguration();//允许所有域名进行跨域调用config.addAllowedOriginPattern("*");// 设置你要允许的网站域名//config.addAllowedOrigin("http://localhost:8081");//允许跨域发送cookieconfig.setAllowCredentials(true);//放行全部原始头信息config.addAllowedHeader("*");//允许所有请求方法跨域调用config.addAllowedMethod("*");UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();source.registerCorsConfiguration("/**", config);return new CorsFilter(source);}
}

代码流程:

1.创建SseEmitter实例

2.准备向前端发送数据

3.建立与前端的连接

4.解决跨域问题

注意:return emitter; 是将这个 SseEmitter 对象返回给客户端,以维持连接。客户端可以通过这个连接持续接收来自服务器的实时消息。调用 emitter.send("向前端传递的数据"); 时,它才会将指定的数据发送给客户端。也就是说 emitter.send()才是用来发送数据的。

你可以理解为 emitter.send() 是用来主动推送消息给客户端的行为,而 return emitter; 是为了确保 SSE 连接的持续性。客户端可以在整个连接生命周期中通过这个连接接收服务器端发送的实时消息。

2.创建Vue项目并在项目的.vue文件中编写以下代码

使用JavaScript 中的 EventSource API 来接收 SSE 事件

<template><div><h1>测试页</h1><h3>接收的消息:{{message}}</h3></div>
</template><script>export default {name: "Test",data(){return{eventSource: null,message: '',}},methods:{//接收后台消息receiveMessage(){this.eventSource = new EventSource('http://localhost:8080/sse/events');//接收成功this.eventSource.onmessage = (event) => {this.message=event.data;};//接收失败this.eventSource.onerror = (error) => {console.error('SSE error:', error);};}},mounted() {this.receiveMessage();},beforeDestroy() {// 关闭 EventSource 连接this.eventSource.close();}}
</script><style scoped></style>

代码流程:

1.创建了EventSource实例,连接到指定的SSE服务端端点(http://localhost:8080/sse/events)

2.处理消息事件,通过 onmessage 事件处理程序,组件监听从服务端推送过来的消息。当服务端发送一条消息时,onmessage 事件处理程序将被调用,其中的 event.data 包含了服务端发送的实际数据。

3.处理错误事件,SSE 连接可能因为一些原因中断,例如网络故障。为了处理这种情况,组件还监听了 onerror 事件,并在发生错误时打印错误信息到控制台。

4.关闭连接,在组件销毁之前(beforeDestroy 钩子中),通过 this.eventSource.close() 关闭 SSE 连接,以确保资源被释放。这是为了防止在组件销毁后持续接收不必要的 SSE 事件。

效果说明

此时前后端就会建立连接,如果在控制台输出 this.message 会发现每隔一段时间就会输出一次“向前端传递的数据”。

使用触发的方式向前端传递数据

修改Java代码:

import com.hgkx.pojo.MyData;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;import java.io.IOException;@RestController
@RequestMapping("/sse")
public class SseController {private SseEmitter emitter;@GetMapping("/events")public SseEmitter streamEvents() throws IOException {emitter = new SseEmitter();// 设置超时处理emitter.onTimeout(() -> {emitter.complete();System.out.println("SSE 连接超时");});// 设置关闭处理emitter.onCompletion(() -> {System.out.println("SSE 连接已完成");});return emitter;}@RequestMapping("/aaa")public void aaa() {if (emitter != null) {try {// 向前端发送消息emitter.send("aaa");} catch (IOException e) {e.printStackTrace();}}}@RequestMapping("/bbb")public void bbb(){if (emitter != null) {try {// 向前端发送消息emitter.send("bbb");} catch (IOException e) {e.printStackTrace();}}}
}

因为刚刚我们说到  emitter.send();  才是用来发送数据的,那么我们只需要将他拿出来在单独设置数据即可,这样当我们访问aaa与bbb的地址时就会向前端发送数据。emitter也可以设置超时处理和关闭处理。当SpringBoot项目启动后用于连接的代码不会执行,只有接收的Vue前端也启动后才会执行。

总结

Server-Sent Events使用起来还是比较方便的,不需要加入额外的库或包,只需要单纯的编写代码就可以了,但是他它只支持单向通信,也就只能用于后端向前端发送消息,SSE在跨域通信时可能遇到一些限制,需要进行额外的配置。最后,由于SSE依赖于HTTP长连接,如果连接数量过多,可能会导致服务器资源不足。

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

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

相关文章

静态HTML引入vue封装组件

在对历史原生html代码使用vue重构项目时&#xff0c;可以利用vue相关组件进行项目优化、实现统一管理&#xff0c;本文结束htmlvue的构建方式&#xff0c;欢迎大家阅读交流。 1、 下载vue.js 可自行到官网下载所需版本或者使用cdn资源 2、封装通用组件 2.1 封装通用实例化m…

MIMIC-IV官方视图解析 - cardiac_marker心脏标记表

今天在学习官方衍生表mimiciv_derived.cardiac_marker心脏标记表时候发现了一些问题&#xff1a; 该表中troponin_t &#xff08;肌钙蛋白t&#xff09;的值结果都是空值null 或者 ___ &#xff08;由于去标识化&#xff09;&#xff0c; 这明显是不合理的 小编查看了该表的官…

MySQL-运维篇-日志

一、错误日志 二、二进制日志 1、介绍 2、日志格式 3、日志查看 4、日志删除 三、查询日志 四、慢查询日志

汽车软件开发模式的5个特点

汽车软件开发属于较为复杂的系统工程&#xff0c;经常让来自不同知识背景的工程师在观点交锋时出现分歧。在解决复杂性和对齐讨论基准时&#xff0c;可以通过勾勒出讨论对象最关键的几个特征来树立典型概念。本文旨在通过5个典型特点的抽取&#xff0c;来勾勒出汽车软件开发模式…

python实现贪吃蛇小游戏(附源码)

文章目录 导入所需的模块坐标主游戏循环模块得分 贪吃蛇小游戏&#xff0c;那个曾经陪伴着00后和90后度过无数欢笑时光的熟悉身影&#xff0c;仿佛是一把打开时光之门的钥匙。它不仅是游戏世界的经典之一&#xff0c;更是我们童年岁月中不可或缺的一部分&#xff0c;一个承载回…

Spring如何进行参数校验

在Java开发中&#xff0c;对输入参数进行校验是一个非常重要的环节&#xff0c;它可以帮助我们避免非法数据对程序造成的影响。Spring框架提供了多种方式进行参数校验&#xff0c;本文将详细介绍如何在Spring中进行参数校验。 一、使用Spring的Validated和Valid注解 Spring提供…

新媒体与传媒行业数据分析实践:从网络爬虫到文本挖掘的综合应用,以“中国文化“为主题

大家好&#xff0c;我是八块腹肌的小胖&#xff0c; 下面将围绕微博“中国文化”以数据分析、数据处理、建模及可视化等操作 目录 1、数据获取 2、数据处理 3、词频统计及词云展示 4、文本聚类分析 5、文本情感倾向性分析 6、情感倾向演化分析 7、总结 1、数据获取 本…

征集各位的意见

1.B站 下一个月我打算在B站开始上传视频教程了&#xff0c;关注我的有一部分是看我TMS320F28377D的&#xff0c;有一部分是看我LPC804M101的&#xff0c;我这里问一下大家想先看哪个教程&#xff1f;好多盆友看我文章里都描述的不是很清楚&#xff0c;可能我上传B站&#xff0…

SwiftUI 动画入门之一:路径动画(Path Animations)

概览 在 SwiftUI 的开发中,我们往往需要使用千姿百态的动画把我们的界面元素妆点的更加鲜活灵动。 如上图所示,我们使用路径动画使折线图更加生动了!这是怎么做到的呢? 在本篇博文中,您将学到以下内容: 概览1. 路径与形状(Path and Shape)2. 路径动画的原理3. 让路径…

Zookeeper服务注册与发现实战

目录 设计思路 Zookeeper注册中心的优缺点 SpringCloudZookeeper实现微服务注册中心 第一步&#xff1a;在父pom文件中指定Spring Cloud版本 第二步&#xff1a;微服务pom文件中引入Spring Cloud Zookeeper注册中心依赖 第三步&#xff1a; 微服务配置文件application.y…

页面切换导致echarts不加载的问题

1. 问题描述 在A页面写了echarts,初始化dom元素加载,显示正常.当切换到B页,再切换回A页面时,echarts加载不出来. f12召唤出来看看报错,没有问题,但是有这样的警告 渲染echarts的dom元素上多了一个" echarts_instance "的属性,这是用来表示唯一性的. 2. 问题解决 …

杂题——试题-算法训练-P0604-runaround数

分析&#xff1a; 题目有三个关键点&#xff1a; 一&#xff1a;结束时&#xff0c;回到起始位置&#xff08;比较结束时和起始时的下标位置是否相同&#xff09;二&#xff1a;该整数的所有数字都必须遍历一遍&#xff0c;且只能遍历一遍&#xff08;把遍历过的数字做个标记&a…

记录下Flybirds移动端ui自动化框架的搭建

一、参考文档 1.官方文档&#xff1a;携程机票跨端跨框架 BDD UI 自动化测试方案Flybirds — flybirds v0.1.5 文档 2.Flybirds运行环境&#xff1a;Flybirds运行环境 - 简书 3.Windows系统连接IOS安装tidevice&#xff1a;iOS自动化之tidevice-CSDN博客 二、Windows系统演…

JavaScript中,异步获取数据通常使用回调函数

在JavaScript中&#xff0c;异步获取数据通常使用回调函数、Promise对象或者async/await来处理。以下是几种常见的方法&#xff1a; 1. 回调函数&#xff1a;可以在异步请求完成后&#xff0c;将获取到的数据作为参数传递给回调函数。例如&#xff1a; function getData(call…

最佳解决Css一隐藏滚动条

最佳解决Css一隐藏滚动条 方法一&#xff1a; <!DOCTYPE html> <html><head><meta charset"utf-8"><meta name"viewport" content"widthdevice-width,initial-scale1.0"></head><style>.element, .…

力扣_字符串2—最长有效括号

题目 给你一个只包含 ‘(’ 和 ‘)’ 的字符串 s s s&#xff0c;找出最长有效&#xff08;格式正确且连续&#xff09;括号子串的长度。 方法 动态规划 d p [ i ] dp[i] dp[i] 表示以 s [ i ] s[i] s[i] 结尾的最长有效括号的长度如果 s [ i ] s[i] s[i] 为左括号&#…

DNS服务实战:使用自定义域名访问Redis服务

前言 在这篇文章中,你将了解到如何在 CentOS 系统上安装 Redis 服务,并且掌握通过自定义域名来访问 Redis 服务的技巧。通过使用自定义域名,你可以方便地管理和访问你的 Redis 数据库,提高工作效率。无论你是开发者、系统管理员还是对 Redis 感兴趣的读者,这篇文章都会为…

springboot145基于java的在线问卷调查系统的设计与实现

简介 【毕设源码推荐 javaweb 项目】基于springbootvue 的 适用于计算机类毕业设计&#xff0c;课程设计参考与学习用途。仅供学习参考&#xff0c; 不得用于商业或者非法用途&#xff0c;否则&#xff0c;一切后果请用户自负。 看运行截图看 第五章 第四章 获取资料方式 **项…

突破编程_C++_基础教程(函数(一))

1 函数声明 函数声明的作用是告诉编译器即将要定义的函数的名字是什么&#xff0c;返回值的类型是什么以及函数是什么。函数的声明可以有多次&#xff0c;但是函数的定义只能有一次。如果只有函数声明没有函数定义&#xff0c;则可以通过编译&#xff0c;但是链接时会报错。 通…

亚信安慧的AntDB数据库:稳定可靠的保障

亚信安慧AntDB数据库在运营商自主可控替换项目中的成功应用&#xff0c;具有极其重要的意义。该数据库的落地&#xff0c;不仅为这一项目注入了强大的支持力量&#xff0c;还在更大程度上提升了整体的运营效能。作为一种高效可靠的数据库解决方案&#xff0c;AntDB引入了先进的…