栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

SseEmitter后端主动推送消息给前端

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

SseEmitter后端主动推送消息给前端

公司有个需求,前端界面需要展示实时展示下单消息。

解决方案:

1.前端间隔一定时常,轮询向后端发送请求,查询下单数据

2.利用长链接,后端向前端主动推送下单消息

果断选择第二种。从以往的经验,首先想到websocket,但是websocket属于双向通道,且服务端比较琐碎,就在网上找了下其他类似技术,看到了SseMmitter,查看了向网上相关文章,及用例。正好符合我们的需求,话不多说,上代码

一、新增see对象

public class SeeResult {
    
    public String clientId;
    public long timestamp;
    public SseEmitter sseEmitter;

    public SeeResult(String clientId, long timestamp, SseEmitter sseEmitter) {
        this.clientId = clientId;
        this.timestamp = timestamp;
        this.sseEmitter = sseEmitter;
    }

}

二、新增连接存储map

public class SseMap {
    public static final Map sseEmitterMap = new ConcurrentHashMap<>();
}

三、新增controller

前端连接我采取的方案时 业务标识+时间戳;例如 1-1652685165648

@Slf4j
@CrossOrigin
@RestController
@RequestMapping("/api/message/see")
public class SseEmitterController {

    
    @GetMapping("/start")
    public SseEmitter testSseEmitter(String clientId) throws IOException{
        if (StringUtils.isBlank(clientId)){
            throw new DeliveryException("参数不能为空");
        }
        // 默认30秒超时,设置为0L则永不超时
        SseEmitter sseEmitter = new SseEmitter(0L);
        SseMap.sseEmitterMap.put(clientId, new SeeResult(clientId, System.currentTimeMillis(), sseEmitter));
        return sseEmitter;
    }

    
    @GetMapping("/send")
    public String setSseEmitter(String clientId) {
        try {
            SeeResult result =  SseMap.sseEmitterMap.get(clientId);
            if (result != null && result.sseEmitter != null) {
                long timestamp = System.currentTimeMillis();
                String re = "{"success":true,"message":"操作成功!","code":200,"result":{"id":1018},"timestamp":1629254216358}";
                result.sseEmitter.send(SseEmitter.event().name("msg").data(re));
            }
        } catch (IOException e) {
            log.error("IOException!", e);
            return "error";
        }

        return "Succeed!";
    }

    
    @GetMapping("/end")
    public String completeSseEmitter(String clientId) {
        SeeResult result =  SseMap.sseEmitterMap.get(clientId);
        if (result != null) {
            SseMap.sseEmitterMap.remove(clientId);
            result.sseEmitter.complete();
        }

        return "Succeed!";
    }

四、前端(Vue)

因连接需要经过网关,token验证。
EventSource EventSource - Web API 接口参考 | MDN相关文档没找到有设置请求头参数的方式
github 上有组件event-source-polyfill,附上地址

GitHub - Yaffle/EventSource: a polyfill for http://www.w3.org/TR/eventsource/

 五、部署至生产环境

nginx配置ssl 443反向代理,前端一直连接不上,但是http协议是正常的。

经过测试,需要nginx 中增加 proxy_buffering off参数

网上查看proxy_buffering 参数详解以及介绍,

proxy_buffering
语法: proxy_buffering on|off
默认值: proxy_buffering on
上下文: http, server, location

这个参数用来控制是否打开后端响应内容的缓冲区,如果这个设置为off,那么proxy_buffers和proxy_busy_buffers_size这两个指令将会失效。 但是无论proxy_buffering是否开启,对proxy_buffer_size都是生效的。

proxy_buffering开启的情况下,nignx会把后端返回的内容先放到缓冲区当中,然后再返回给客户端(边收边传,不是全部接收完再传给客户端)。 临时文件由proxy_max_temp_file_size和proxy_temp_file_write_size这两个指令决定的。如果响应内容无法放在内存里边,那么部分内容会被写到磁盘上。

如果proxy_buffering关闭,那么nginx会立即把从后端收到的响应内容传送给客户端,每次取的大小为proxy_buffer_size的大小,这样效率肯定会比较低。
nginx不尝试计算被代理服务器整个响应内容的大小,nginx能从服务器接受的最大数据,是由指令proxy_buffer_size指定的.

注:1、 proxy_buffering启用时,要提防使用的代理缓冲区太大。这可能会吃掉你的内存,限制代理能够支持的最大并发连接数。

2、对于基于长轮询(long-polling)的Comet 应用来说,关闭 proxy_buffering 是重要的,不然异步响应将被缓存导致Comet无法工作

但是不知道和https和http有什么关系?
 

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/894683.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号