Java后端 服务器单向实时推送消息

前言:

如果有人购买商品,后台实时推送一个消息到用户。如果用websocket来做还需要写websocket服务器和配置。用轮询,会影响服务器性能之外,还达不到实时效果。有没有别的选择呢?当然有!

一、简介:Server-Sent 事件指的是网页自动获取来自服务器的更新。

二、局限性:
1.WebSocket 比 SSE 更强大,Websocket 在客户端和服务器之间建立了双向的实时通信。而 SSE 只支持从服务器到客户端的单向实时通信。
2.WebSocket 在浏览器方面支持更全面,IE / Edge 几乎根本不支持 SSE
如果业务上不考虑浏览器的兼容性仅需要服务器推送消息,实时更新的功能,建议优先选择SSE。

三、优势性:
1.SSE 实现内置断线重连和消息追踪的功能,WebSocket 也能实现,但是不在协议设计范围内,需要手动处理。
2.SSE 实现简单,完全复用现有的 HTTP 协议,而 WebSocket 是相对独立于 HTTP 的一套标准,跨平台实现较为复杂。

四、适合功能:Facebook/Twitter 更新、股价更新、新的博文、赛事结果等

五、服务器后端代码
服务器端的响应的内容类型是“text/event-stream” 必须写,编码可写可不写,最好是写上。
下面展示核心 代码块

@RestController
public class MySysMessageEvent {
    private final static Logger logger = Logger.getLogger(MySysMessageEvent.class);

    public static final Map<String, SseEmitter> SSE_HOLDER = new ConcurrentHashMap<>();

    @GetMapping(value = "/messageSSE/{userid}", produces = "text/event-stream;charset=UTF-8")
    public SseEmitter messageSSE(HttpSession session, @PathVariable String userid) {
        long millis = TimeUnit.SECONDS.toMillis(30*60);
        //设置存活时间
        SseEmitter sseEmitter = new SseEmitter(millis);
        String sessionid = session.getId();
        //userid与sessionid进行绑定
        String newId = sessionid + "|" + userid;
        SSE_HOLDER.put(newId, sseEmitter);
        userSsePush(newId, "连接成功!");
        logger.info("SSE连接成功!");
        return sseEmitter;
    }

    /**
     * 通过sessionId获取对应的客户端进行推送消息
     */
    public static void userSsePush(String sessionid, String content) {
        SseEmitter emitter = MySysMessageEvent.SSE_HOLDER.get(sessionid);
        if (Objects.nonNull(emitter)) {
            try {
                emitter.send(content);
            } catch (IOException | IllegalStateException e) {
                e.printStackTrace();
                logger.warn("sse send error", e);
                MySysMessageEvent.SSE_HOLDER.remove(sessionid);
            }
        }
    }
}
  • 注释: SseEmitter是springframework 中 SpringMVC提供的,它是基于Http协议的,相比WebSocket,它更轻量,但是它只能从服务端向客户端单向发送信息。

六、如果需要在业务上直接将此代码复用即可:

 Set<String> key = MySysMessageEvent.SSE_HOLDER.keySet();
                    Iterator<String> iterator = key.iterator();
                    while (iterator.hasNext()) {
                        String e = iterator.next();
                        if (Integer.valueOf(e.split("[|]")[1]).equals(approve.getUserid())) {//----此语句根据业务修改
                           MySysMessageEvent.userSsePush(e, "您有新的消息,请尽快查收!");
                       }
                   }

七、注意:有nginx代理的才需要此步骤
需要查看是否有nginx拦截,如果有拦截,需要在nginx配置上配置

location /messageSSE {
proxy_http_version 1.1;
# proxy_request_buffering off;
# proxy_buffering off;
# proxy_cache off;
# chunked_transfer_encoding off;
proxy_set_header Connection '';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://localhost:28080/messageSSE;
}

友情提示:由于SSE的局限性,导致无法广泛使用,相应处理问题的方法会缺乏,在使用该功能时需要去搞清楚,将来业务是否会有所改动,能否及时去处理,如果有困难,请斟酌考量去使用!

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值