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

目录

概述

[使用 Server-Sent Events (SSE)](#使用 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类,用于传递数据

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 {
        SseEmitter emitter = new SseEmitter();

        emitter.send("向前端传递的数据");

        return emitter;
    }
}

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

java 复制代码
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 {

    @Bean
    public CorsFilter corsFilter() {
        CorsConfiguration config = new CorsConfiguration();
        //允许所有域名进行跨域调用
        config.addAllowedOriginPattern("*");
        // 设置你要允许的网站域名
        //config.addAllowedOrigin("http://localhost:8081");
        //允许跨域发送cookie
        config.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 事件

html 复制代码
<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代码:

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长连接,如果连接数量过多,可能会导致服务器资源不足。

相关推荐
耶啵奶膘1 小时前
uniapp-是否删除
linux·前端·uni-app
魔道不误砍柴功2 小时前
Java 中如何巧妙应用 Function 让方法复用性更强
java·开发语言·python
NiNg_1_2342 小时前
SpringBoot整合SpringSecurity实现密码加密解密、登录认证退出功能
java·spring boot·后端
闲晨2 小时前
C++ 继承:代码传承的魔法棒,开启奇幻编程之旅
java·c语言·开发语言·c++·经验分享
种树人202408192 小时前
如何在 Spring Boot 中启用定时任务
spring boot
王哈哈^_^3 小时前
【数据集】【YOLO】【目标检测】交通事故识别数据集 8939 张,YOLO道路事故目标检测实战训练教程!
前端·人工智能·深度学习·yolo·目标检测·计算机视觉·pyqt
Chrikk3 小时前
Go-性能调优实战案例
开发语言·后端·golang
幼儿园老大*3 小时前
Go的环境搭建以及GoLand安装教程
开发语言·经验分享·后端·golang·go
canyuemanyue3 小时前
go语言连续监控事件并回调处理
开发语言·后端·golang
杜杜的man3 小时前
【go从零单排】go语言中的指针
开发语言·后端·golang