Js即时通讯技术 - SSE(SpringBoot实现)

目录

一、前言

二、SpringBoot实现

1.Controller

2.index.html

3.测试


一、前言

主流的Web端即时通讯方案大致有4种:传统Ajax短轮询、Comet技术、WebSocket技术、SSE(Server-sent Events)。

 Ajax短轮询CometWebSocketSSE
概念http端轮询是服务器收到请求不管是否有数据都直接响应 http 请求; 浏览器受到 http 响应隔一段时间在发送同样的http 请求查询是否有数据;http 长轮询是服务器收到请求后如果有数据, 立刻响应请求; 如果没有数据就会 hold 一段时间,这段时间内如果有数据立刻响应请求; 如果时间到了还没有数据, 则响应 http 请求;浏览器受到 http 响应后立在发送一个同样http 请求查询是否有数据;WebSocket的实现了一次连接,双方通信的功能。首先由客户端发出WebSocket请求,服务器端进行响应,实现类似TCP握手的动作。这个连接一旦建立起来,就保持在客户端和服务器之间,两者之间可以直接的进行数据的互相传送。在 sse 的场景下,客户端发起请求,连接一直保持,服务端有数据就可以返回数据给客户端,这个返回可以是多次间隔的方式。sse 是单通道,只能服务端向客户端发消息
协议httphttpwbSocket

http

 短轮询长轮询  

 

 

 

 

 

二、SpringBoot实现

1.Controller

使用接口模拟发送消息

package com.asyf.demo.controller;

import cn.hutool.core.date.DateUtil;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;

import java.io.IOException;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;


@Controller
@RequestMapping(path = "sse")
public class SSEController {

    @GetMapping(path = "")
    public String index() {
        //index.html在static/index.html目录
        return "index.html";
    }

    @RequestMapping(value = "test", method = RequestMethod.GET)
    public Object test() {
        return DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss");
    }

    private static Map<String, SseEmitter> sseCache = new ConcurrentHashMap<>();

    @GetMapping(path = "subscribe")
    public SseEmitter push(String id) throws IOException {
        System.out.println(id);
        // 超时时间设置为1小时
        SseEmitter sseEmitter = new SseEmitter(3600_000L);
        // 设置前端的重试时间为1s
        sseEmitter.send(SseEmitter.event().reconnectTime(1000).data("连接成功"));
        sseCache.put(id, sseEmitter);
        sseEmitter.onTimeout(() -> sseCache.remove(id));
        sseEmitter.onCompletion(() -> System.out.println("完成!!!"));
        return sseEmitter;
    }

    @GetMapping(path = "push")
    @ResponseBody
    public String push(String id, String content) throws IOException {
        SseEmitter sseEmitter = sseCache.get(id);
        if (sseEmitter != null) {
            sseEmitter.send(content);
        }
        return "push over";
    }

    @GetMapping(path = "close")
    @ResponseBody
    public String over(String id) throws IOException {
        SseEmitter sseEmitter = sseCache.get(id);
        if (sseEmitter != null) {
            sseEmitter.send("close");
            sseEmitter.send(SseEmitter.event().name("close").id(id).data(""));
            sseEmitter.complete();
            sseCache.remove(id);
        }
        return "close over";
    }

}

2.index.html

目录是resourses/static/index.html

<!doctype html>
<html lang="en">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title>SSE测试</title>
</head>
<body>
<div>sse测试</div>
<div id="result"></div>
</body>
</html>
<script>
    function msg(msg) {
        console.log(msg)
        var div = document.createElement('div');
        div.innerHTML = msg;
        document.getElementById('result').appendChild(div);
    }

    //判断浏览器是否支持SSE
    if (!!window.EventSource) {
        var source = new EventSource('http://localhost:8080/sse/subscribe?id=ssetest');

        //响应消息-实现方式1
        // source.onmessage = function (event) {
        //     text = document.getElementById('result').innerText;
        //     text += '\n' + event.data;
        //     document.getElementById('result').innerText = text;
        // };

        //响应消息-实现方式2
        source.addEventListener('message', function (e) {
            msg(e.data);
        }, false);

        //响应open事件
        source.addEventListener('open', function (e) {
            msg("连接打开.");
        }, false);

        // 响应close事件,主动关闭EventSource
        //后端关闭SSE会执行error事件,在error事件中关闭SSE不友好,后端在关闭SSE发送close
        // 事件以友好的关闭SSE
        source.addEventListener('close', function (e) {
            source.close();
            console.log(e);
            msg("数据接收完毕,关闭EventSource");
        }, false);

        //响应error事件
        source.addEventListener('error', function (e) {
            if (e.readyState == EventSource.CLOSED) {
                msg("连接关闭");
            } else {
                console.log(e);
            }
        }, false);

    } else {
        console.log("你的浏览器不支持SSE");
        msg("你的浏览器不支持SSE");
    }

</script>

3.测试

首页:http://localhost:8080/sse

发送消息:http://localhost:8080/sse/push?id=ssetest&content=%E6%B5%8B%E8%AF%95%E6%95%B0%E6%8D%AE

关闭连接:http://localhost:8080/sse/close?id=ssetest

 

 

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Django-sse是一个Django应用,它提供了一种实现服务器发送事件(Server-Sent Events)的方式。在Django-sse中,服务器可以向客户端推送新的消息,而客户端则可以通过EventSource API接收这些消息。以下是使用Django-sse实现服务器发送事件的基本步骤: 1. 安装Django-sse 可以使用pip命令进行安装: ``` pip install django-sse ``` 2. 创建视图函数 在Django中创建一个视图函数,该函数用于处理客户端的请求并向客户端发送事件。以下是示例代码: ```python from django_sse.views import BaseSseView class MySseView(BaseSseView): def iterator(self): # 在这里生成要发送给客户端的事件 yield 'event: my_event\n' yield 'data: {}\n\n'.format('hello world') ``` 在上面的代码中,我们继承了Django-sse提供的BaseSseView类,并实现了iterator方法。该方法用于生成要发送给客户端的事件。在这里,我们生成了一个名为“my_event”的事件,并附带了一个“hello world”的消息。 3. 添加URL 在Django中添加一个URL,将其映射到上面创建的视图函数。以下是示例代码: ```python from django.urls import path from .views import MySseView urlpatterns = [ path('my-sse-view/', MySseView.as_view(), name='my_sse_view'), ] ``` 4. 在客户端使用EventSource 在客户端使用JavaScript代码创建一个EventSource对象,指定上面添加的URL。以下是示例代码: ```javascript var source = new EventSource('/my-sse-view/'); source.addEventListener('my_event', function(event) { console.log(event.data); }); ``` 在上面的代码中,我们创建了一个名为“my_event”的事件监听器,并在控制台中打印了接收到的消息。 以上就是使用Django-sse实现服务器发送事件的基本步骤。需要注意的是,在实际应用中,我们需要根据具体需求生成不同类型的事件,并在事件监听器中处理这些事件。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值