首先了解什么SSE服务?
SSE(Server-Sent Events,服务器发送事件)是一种基于 HTTP 的服务器向客户端单向推送实时数据的技术,它允许服务器主动向客户端发送事件流,适用于实时通知、数据更新等场景
特点:
- 单向通信:仅服务器向客户端推送数据(客户端不能通过 SSE 向服务器发送数据,需用 HTTP 或 WebSocket 补充)。
- 基于 HTTP:复用 HTTP 连接,无需额外协议(WebSocket 是独立协议),兼容性更好。
- 自动重连:客户端断开连接后会自动重试(可配置重连时间)。
- 文本数据:传输的数据是 UTF-8 编码的文本(通常用 JSON 格式)。
- 轻量级:协议简单,实现成本低,适合简单的实时场景。
java
@Slf4j
public class SSEServer {
//存放所有用户的SseEmitter
private static final Map<String, SseEmitter> SSE_EMITTER_MAP=new ConcurrentHashMap<>();
/**
* 连接SSE
* @return
*/
public static SseEmitter connect(String userId){
//设置超时时间,0表示不超时;默认是30秒,超时会抛出异常
SseEmitter sseEmitter=new SseEmitter(0L);
//注册回调方法
//超时回调
sseEmitter.onTimeout(timeOutCallBack(userId));
//SSE完成后回调,完成后会调用的方法
sseEmitter.onCompletion(completionCallBack(userId));
//异常回调
sseEmitter.onError(errorCallBack(userId));
SSE_EMITTER_MAP.put(userId,sseEmitter);
log.info("用户{}连接SSE成功",userId);
return sseEmitter;
}
/**
* 发送SSE消息
* @param userId
* @param message
* @param msgType
*/
public static void senMessage(String userId,String message,SSEMsgType msgType){
if (CollectionUtil.isEmpty(SSE_EMITTER_MAP)){
return;
}
if (SSE_EMITTER_MAP.containsKey(userId)) {
SseEmitter sseEmitter = SSE_EMITTER_MAP.get(userId);
//发送事件
sendEvent(sseEmitter,userId,message,msgType);
}
}
/**
* 发送SSE事件
* @param sseEmitter
* @param userId
* @param message
* @param msgType
*/
private static void sendEvent(SseEmitter sseEmitter,
String userId,
String message,
SSEMsgType msgType){
try{
SseEmitter.SseEventBuilder eventBuilder = SseEmitter.event()
.id(userId)
.name(msgType.type)
.data(message);
sseEmitter.send(eventBuilder);
}catch (Exception e){
log.error("用户{}发送SSE消息异常",userId,e);
remove(userId);
}
}
/**
* 异常回调
* @param userId
* @return
*/
public static Consumer<Throwable> errorCallBack(String userId){
return throwable -> {
log.error("用户{}SSE连接异常",userId,throwable);
//异常处理逻辑
remove(userId);
};
}
/**
* 超时回调
* @param userId
* @return
*/
public static Runnable timeOutCallBack(String userId){
return () -> {
log.info("用户{}超时",userId);
//超时处理逻辑
remove(userId);
};
}
/**
* 完成回调
* @param userId
* @return
*/
public static Runnable completionCallBack(String userId){
return () -> {
log.info("用户SSE{}完成",userId);
//完成处理逻辑
remove(userId);
};
}
/**
* 移除用户的SseEmitter
* @param userId
*/
public static void remove(String userId){
SSE_EMITTER_MAP.remove(userId);
log.info("移除用户{}的SseEmitter",userId);
}
}
定义枚举类型,代表SSE返回的消息类型
java
/**
* SSE消息类型
*/
public enum SSEMsgType {
MESSAGE("message","单词发送的普通类型消息"),
ADD("add","消息追加,适用于流式消息"),
FINISH("finish","消息完成"),
CUSTOM_EVENT("custom_event","自定义事件"),
DONE("done","消息完成,适用于流式消息");
public final String type;
public final String value;
SSEMsgType(String type,String value){
this.type=type;
this.value=value;
}
}