目录
[使用 Server-Sent Events (SSE)](#使用 Server-Sent Events (SSE))
1.创建SpringBoot项目添加web依赖,并编写以下代码
概述
在典型的前后端分离架构中,前端通过发起 HTTP 请求(例如使用 Axios 或 Fetch API)向后端发送请求,后端处理这些请求并返回响应。这种模式是常见的,并符合常规的网络通信方式。
然而,有时候确实存在一些特殊情况或需求,需要后端通过主动推送的方式与前端进行通信。这通常使用 WebSocket 或 Server-Sent Events (SSE) 技术来实现。WebSocket 通常更适合实时双向通信,而 SSE 更适合单向通知。本文主要使用 Server-Sent Events 实现。
使用 Server-Sent Events (SSE)
Server-Sent Events (SSE) 允许服务器单向推送事件到浏览器。在 Spring Boot 中,使用 SseEmitter
或 ResponseBodyEmitter
类来实现 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长连接,如果连接数量过多,可能会导致服务器资源不足。