美文网首页
服务端通过SSE向前端推送消息

服务端通过SSE向前端推送消息

作者: Stalary | 来源:发表于2018-07-22 18:44 被阅读0次

    SSE(Server-Sent Events)相比Websocket来说更加轻量,在代码书写时也更加的方便,所以今天来讲一下SSE的简单使用。

    当时接到一个需求是上传word进行解析题目存储,并且前端要显示解析过程,当时首先想到的就是Websocket,后来仔细一想,有没有更轻量级的方法呢,果然还是有的

    下面来讲一下具体的使用方法

    1. 我们使用Spring项目来进行讲解,所以需要引入的Spring依赖就不再说明了,然后我们可以惊奇的发现引入完Spring的一些依赖,我们竟然就可以使用SSE了。果然够轻量

    2. 通过以下简单的代码我们就完成了SSE消息的发送,一个方法通过sse监控解析进度,一个方法进行文件解析

    /**
         * sse
         */
        @GetMapping("/sse")
        public SseEmitter getSSE(
                HttpServletRequest request) {
            SseEmitter emitter;
            String userId = UserUtils.getUserId(request);
            if (userMap.containsKey(userId)) {
                emitter = userMap.get(userId);
            } else {
                emitter = new SseEmitter();
                userMap.put(userId, emitter);
                emitter.onTimeout(() -> userMap.remove(userId));
            }
            return emitter;
        }
        @PostMapping("/submit")
        public ResponseMessage submit(
                HttpServletRequest request,
                @RequestParam MultipartFile file,
                @RequestParam String category,
                @RequestParam String type,
                @RequestParam(required = false, defaultValue = "") String year) {
            String editor = UserUtils.getUserId(request);
            return ResponseMessage.successMessage(uploadService.upload(file, category, type, year, editor));
        }
    

    返回数据

    data:"文件开始解析"
    event:upload_start
    
    1. 接下来说一下我们该如何进行解析操作
    /**
         * 存储解析进度key:userId,value:schedule
         */
        private final Map<String, Integer> scheduleMap = Maps.newConcurrentMap();
    
        /**
         * 是否已经完成解析key:userId,value:是否已经完成
         */
        private final Map<String, Boolean> isFinishedMap = Maps.newConcurrentMap();
    
        /**
         * 解析完成后返回的数据
         */
        private final Map<String, Map<String, Object>> returnMap = Maps.newConcurrentMap();
        @Scheduled(fixedRate = 500)
        public void uploadSchedule() {
            for (Map.Entry<String, SseEmitter> entry : UploadCtrl.userMap.entrySet()) {
                try {
                    String userId = entry.getKey();
                    Boolean isFinished = isFinishedMap.get(userId);
                    if (isFinished == null) {
                        return;
                    }
                    if (!isFinished) {
                        SseEmitter.SseEventBuilder builder = SseEmitter
                                .event()
                                .data(scheduleMap.get(userId))
                                .name("upload_schedule");
                        entry.getValue().send(builder);
                        log.info("sse send" + userId + " schedule: " + scheduleMap.get(userId));
                    } else {
                        // 代表解析完毕
                        SseEmitter.SseEventBuilder builder = SseEmitter
                                .event()
                                .data(returnMap.get(userId))
                                .name("upload_end");
                        entry.getValue().send(builder);
                        log.info("sse send" + userId + " end: " + gson.toJson(returnMap.get(userId)));
                        // 解析完毕后从Map中移除
                        UploadCtrl.userMap.remove(userId);
                        isFinishedMap.remove(userId);
                        scheduleMap.remove(userId);
                        returnMap.remove(userId);
                        // 关闭emitter
                        entry.getValue().complete();
                    }
                } catch (Exception e) {
                    log.warn("upload Error of " + entry.getKey(), e);
                    UploadCtrl.userMap.remove(entry.getKey());
                }
            }
        }
    

    可以看出我通过是否完成map,解析结果map,解析进度map来进行解析进度的存储,然后通过定时任务,每0.5s向前端发送一次进度。

    我们可以发现,使用SSE推送消息是十分的方便快捷的,并且自身封装有一些失败重试,自动重连的机制,相比websocket来说,使用更加方便。

    今天前端同事对接接口,才发现sse是没法使用post方法的,这一点大家要注意,所以对博客进行了更改

    每当我们想要松懈时,就想想之前的汗水,那是我们今天所拥有的一切的源泉

    相关文章

      网友评论

          本文标题:服务端通过SSE向前端推送消息

          本文链接:https://www.haomeiwen.com/subject/jyqrmftx.html