工作记录关于只需要服务端向web端单向通知的技术SSE的技术落地总结
最近有个需求是关于消息的单向通知,原本考虑用websocket,但是技术经理认为太重,建议采用SSE.
查阅相关技术后 结合实际业务需要新建了一个工具类
@Component
@Slf4j
public class SSEUtils {
private final Map<String, SseEmitter> pool = new ConcurrentHashMap<String, SseEmitter>();
/**
* sse发送消息
*
* @param ids
* @param content
*/
public void sendMessageBySSE(List<String> ids, SysMessageBase content) {
log.info("SSE对象暂存池数据={}" ,pool );
for (String id : ids) {
SseEmitter sseEmitter = pool.get(id);
if (ObjectUtil.isNull(sseEmitter)) {
//0L表示一致存在
sseEmitter = new SseEmitter(0L);
// sseEmitter.onCompletion(()->pool.remove(id));
sseEmitter.onTimeout(() -> pool.remove(id));
pool.put(id, sseEmitter);
}
try {
sseEmitter.send(content);
} catch (IOException e) {
e.printStackTrace();
}
}
}
public SseEmitter subscribe(String id) {
SseEmitter sseEmitter = pool.get(id);
if (ObjectUtil.isNull(sseEmitter)) {
//1000秒 3600000L
sseEmitter = new SseEmitter(0L);
// sseEmitter.onCompletion(() -> pool.remove(id));
sseEmitter.onTimeout(() -> pool.remove(id));
pool.put(id, sseEmitter);
}
return sseEmitter;
}
// @Scheduled(cron ="*/2 * * * * ?")
// public void sendDemo() {
// if (ObjectUtil.isNotNull(pool.keySet().size())&&pool.keySet().size()>0){
// SysMessageBase sysMessage = new SysMessageBase();
// sysMessage.setTitle("测试SSE消息定时发送");
// for (String key : pool.keySet()) {
// SseEmitter sseEmitter = pool.get(key);
// if (ObjectUtil.isNull(sseEmitter)) {
// //0L表示一致存在
// sseEmitter = new SseEmitter(0L);
// sseEmitter.onCompletion(()->pool.remove(key));
// sseEmitter.onTimeout(() -> pool.remove(key));
// pool.put(key, sseEmitter);
// }
// try {
// sseEmitter.send(sysMessage);
// } catch (IOException e) {
// e.printStackTrace();
// }
// }
// }else {
// SseEmitter sseEmitter = new SseEmitter(0L);
// pool.put("80", sseEmitter);
// }
//
//
// }
public void loginOut(String id) {
SseEmitter sseEmitter = pool.get(id);
if (ObjectUtil.isNotNull(sseEmitter)) {
pool.remove(id);
}
}
}
@Resource
SSEUtils sseUtils;
@GetMapping(value = "/getSseById", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public SseEmitter subscribe(@RequestParam("id") String id){
return sseUtils.subscribe(id);
}
在本地使用postman测试后没有问题,但是在部署测试环境和前端联调时发现。接口无法调用,查阅相关资料后发现SSE自身不支持跨域,需要在代理中配置。
网上相关的资料都显示只要在原ser中新建loca例如以下![在这里插入图片描述](/i/ll/?i=direct/1fd61a95ec474f99b15552e3ef836f1d.png)
但是在重新部署nginx后发现依然无法调用。在后面技术经理的支持下,解决了这个问题。
解决方式是需要给SSE新建一个ser
![在这里插入图片描述](/i/ll/?i=direct/0e1e80bafef144b4b65105814fe694a3.png)
尝试后,前后端正常调用。