服务器往浏览器推消息(SSE)应用

1,SSE 和 WebSocket 对比

SSE(服务器发送事件)

SSE是一种基于HTTP的单向通信机制,用于服务器向客户端推送数据。它的工作原理如下:

建立连接:客户端通过发送HTTP请求与服务器建立连接。在请求中,客户端指定了接收事件的终点(Endpoint)。

保持连接:服务器接收到连接请求后,保持连接打开,并定期发送事件数据给客户端。

事件流:服务器使用 "Content-Type: text/event-stream" 头部标识SSE连接,并使用特定格式的数据(事件流)发送给客户端。

客户端处理事件:客户端通过JavaScript的 EventSource 接口监听SSE连接,一旦接收到事件,就可以处理数据并更新页面。

SSE的特点和适用场景:

单向通信:SSE是从服务器到客户端的单向通信模型,只能由服务器推送数据给客户端。

实时更新:SSE适用于需要实时更新数据的应用场景,如股票行情、新闻推送等。

简单易用:使用SSE相对简单,无需额外的库或框架支持,可以直接使用浏览器的原生API进行开发。

WebSocket

WebSocket是一种全双工的通信协议,它通过在客户端和服务器之间建立持久连接,实现双向通信。WebSocket的工作原理如下:

握手阶段:客户端向服务器发送WebSocket握手请求,服务器返回握手响应。在这个阶段,客户端和服务器协商选择协议和版本。

建立连接:握手成功后,客户端和服务器之间建立持久连接,可以进行双向数据传输。

双向通信:一旦连接建立,客户端和服务器都可以主动发送消息给对方。数据可以以文本或二进制格式进行传输。

断开连接:当任一方决定关闭连接时,可以发送关闭帧来终止连接。

WebSocket的特点和适用场景:

双向通信:WebSocket支持双向通信,客户端和服务器可以互相发送消息。

实时互动:WebSocket适用于实时互动的应用场景,如聊天应用、协作编辑等。

复杂性和灵活性:相对于SSE,WebSocket更为灵活,可以处理更复杂的通信需求。它允许自定义消息格式、心跳检测、连接状态管理等。

2,具体代码实现

2.1 后端

java 复制代码
    @GetMapping(value = "/stock",produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public SseEmitter streamStockPrice() {
        SseEmitter emitter = new SseEmitter();
        // 模拟生成实时股票价格并推送给客户端
        Random random = new Random();
        new Thread(() -> {
            try {
                while (true) {
                    // 生成随机的股票价格
                    double price = 100 + random.nextDouble() * 10;
                    // 构造股票价格的消息
                    String message = String.format("%.2f", price);
                    // 发送消息给客户端
                    emitter.send(SseEmitter.event().data(message));
                    // 休眠1秒钟
                    Thread.sleep(1000);
                }
            } catch (Exception e) {
                emitter.completeWithError(e);
            }
        }).start();
        return emitter;
    }

2.2 前端

javascript 复制代码
    $("#btn12").click(function (){
        const eventSource = new EventSource('http://localhost:8080/test/test/stock');
        eventSource.onmessage = function (event) {
            showMsg(event.data)
        }
    })

2.3 最终效果

SSE 演示

3,传统部署方式

nginx部署

4,k8s部署方式

待研究

5,问题

问题 1:采用 nginx 部署时,页面刷新很慢,实际上服务器已经发了很多数据过来。

此问题待研究解决。

解决方法:

nginx 做相关配置

配置如下

bash 复制代码
         location /codeTest {
            proxy_pass http://127.0.0.1:18080/test;

            # proxy_http_version设置代理使用的HTTP协议版本为1.1。
            proxy_http_version 1.1;
            proxy_set_header Connection "";
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header Host $host;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

            # SSE 连接时的超时时间
            proxy_read_timeout 86400s;

            # 取消缓冲
            proxy_buffering off;
            # 关闭代理缓存
            proxy_cache off;
            # 禁用分块传输编码
            #chunked_transfer_encoding off
        }

/codeTest是你希望使用的路径,你可以根据需要进行修改。 proxy_pass指定了后端服务器的地址,你需要将其替换为实际的后端服务器地址。

proxy_http_version设置代理使用的HTTP协议版本为1.1。

proxy_set_header设置一些必要的头部信息,如连接方式、真实客户端IP等。

proxy_read_timeout 指令来设置 SSE 连接的超时时间。默认情况下,Nginx 会在 60 秒后关闭空闲的连接,这对于 SSE 来说是不合适的,所以我们将超时时间设置为一天(86400 秒)。这样,客户端和服务器之间的连接可以持续保持打开状态。

proxy_buffering off 指令来确保数据可以实时传输,而不需要等待缓冲区满。在SSE请求中禁用缓冲,以便正确处理SSE流式数据。

proxy_cache 对于 SSE(Server-Sent Events)连接,通常不建议启用 Nginx 的代理缓存(proxy_cache)。因为 SSE 是一种长连接技术,它通过保持持久连接来实时推送数据给客户端,而代理缓存会将响应数据缓存起来并在后续请求中返回缓存的响应,这与 SSE 的工作方式相违背。如果启用代理缓存,Nginx 可能会缓存 SSE 的数据,并在后续的连接中返回相同的缓存数据,这样会导致客户端收到重复的消息,破坏了 SSE 的实时性和准确性。

chunked_transfer_encoding 参数可以根据你的需求决定是否关闭。在 SSE 中,通常不需要禁用分块传输编码,因为它允许将数据以数据块的形式逐步传输,与 SSE 的流式数据特性相符合。

proxy_pass 指令正确反向代理到你的 SSE 应用程序的地址和端口,以使连接正确工作。

问题 2:连接一段时候,自动断开

解决方法参考如下文章

Springboot调整接口响应返回时长(解决响应超时问题)

相关推荐
七星静香14 分钟前
laravel chunkById 分块查询 使用时的问题
java·前端·laravel
Jacob程序员15 分钟前
java导出word文件(手绘)
java·开发语言·word
ZHOUPUYU15 分钟前
IntelliJ IDEA超详细下载安装教程(附安装包)
java·ide·intellij-idea
stewie618 分钟前
在IDEA中使用Git
java·git
Elaine20239133 分钟前
06 网络编程基础
java·网络
G丶AEOM35 分钟前
分布式——BASE理论
java·分布式·八股
落落鱼201336 分钟前
tp接口 入口文件 500 错误原因
java·开发语言
想要打 Acm 的小周同学呀37 分钟前
LRU缓存算法
java·算法·缓存
镰刀出海40 分钟前
Recyclerview缓存原理
java·开发语言·缓存·recyclerview·android面试
阿伟*rui3 小时前
配置管理,雪崩问题分析,sentinel的使用
java·spring boot·sentinel