Android消息推送 SSE(Server-Sent Events)方案实践

news2024/11/16 8:50:28

转载请注明出处:https://blog.csdn.net/kong_gu_you_lan/article/details/135777170

本文出自 容华谢后的博客

0.写在前面

最近公司项目用到了消息推送功能,在技术选型的时候想要找一个轻量级的方案,偶然看到一篇文章讲ChatGPT的对话机制是基于SSE来实现的,但是这种协议是基于Web的,客户端能不能用呢,搜索一番发现老朋友OkHttp已经贴心的准备好了一个SSE依赖库,于是便有了这篇文章。

简单介绍下SSE协议,全称Server-Sent Events,2008年首次出现在HTML5规范中,在2014年随着HTML5被W3C推荐为标准,SSE也登上了舞台。作为HTML5的一部分,旨在提供一种简单的机制,用于服务器向客户端推送实时事件数据。

SSE建立在标准的HTTP协议之上,使用普通的HTTP连接,与WebSocket不同的是,SSE是一种单向通信协议,只能是服务器向客户端推送数据,客户端只需要建立连接,而后续的数据推送由服务器单方面完成。

SSE推送流程:

SSE推送流程

1.服务端实现

服务端使用Node.js和Express框架来实现:

const express = require('express');
const http = require('http');
const app = express();
const server = http.createServer(app);

// 静态文件目录,发送消息使用
const path = require('path');
app.use(express.static(path.join(__dirname, 'public')));

// 用于存储连接的客户端响应对象
const clients = [];

// SSE长连接
app.get('/events', (req, res) => {
  // 设置响应头,指定事件流的Content-Type
  res.setHeader('Content-Type', 'text/event-stream; charset=utf-8');
  res.setHeader('Cache-Control', 'no-cache');
  res.setHeader('Connection', 'keep-alive');

  // 发送初始数据
  res.write('data: SSE 已连接\n\n');

  // 将客户端的响应对象存储起来
  clients.push(res);

  // 当连接断开时从数组中移除响应对象
  req.on('close', () => {
    clients.splice(clients.indexOf(res), 1);
  });
});

// 用于接收字符串类型的消息并发送给所有连接的客户端
app.post('/push', express.urlencoded({ extended: true }), (req, res) => {
  const message = req.body.message;

  // 向所有连接的客户端发送消息
  clients.forEach(client => {
    client.write(`data: 收到消息: ${message},连接数:${clients.length}\n\n`);
  });

  res.status(200).send('Message sent successfully');
});

const PORT = process.env.PORT || 3000;
server.listen(PORT, () => {
  console.log(`Server listening on port ${PORT}`);
});

运行命令:

// 初始化项目
npm init -y

// 安装Express
npm install express

// 启动服务端
node server.js

在服务端中定义了两个接口,/events 接口用于客户端请求的长连接服务,/push 接口用于接收控制台发送的消息,然后转发给已连接的所有客户端。

可以注意到events接口中,和普通接口主要的区别在响应头的设置:

res.setHeader('Content-Type', 'text/event-stream; charset=utf-8');
res.setHeader('Cache-Control', 'no-cache');
res.setHeader('Connection', 'keep-alive');
  • Content-Type 指定了响应内容的类型为 text/event-stream,表明这是一个SSE响应。

  • Cache-Control 是控制缓存行为的HTTP头部之一。no-cache 意味着客户端不应该缓存响应。由于SSE是基于长连接的实时通信,而不是通过短轮询获得数据,因此不希望客户端缓存响应,以确保每次都能接收到实时的事件数据。

  • Connection 指示服务器保持与客户端的连接处于打开状态。keep-alive 表示持久连接,允许多个请求和响应在单个连接上交替发送,而不必为每个请求都重新建立连接。在SSE中,保持连接的状态使得服务器能够随时向客户端推送事件,而不必反复建立连接,提高了效率。

2.客户端实现

在项目的build.gradle中增加OkHttp的依赖:

dependencies {
    // OkHttp
    implementation("com.squareup.okhttp3:okhttp:4.12.0")
    implementation("com.squareup.okhttp3:okhttp-sse:4.12.0")
}

OkHttp提供了一个RealEventSource类来实现SSE连接,其中回调了连接、断开、错误和接收消息推送的方法,和普通的OkHttp请求没有太大区别:

val request = Request.Builder()
    .url(binding.etUrl.text.toString())
    .build()
val okHttpClient = OkHttpClient.Builder().also {
    it.connectTimeout(1, TimeUnit.DAYS)
    it.readTimeout(1, TimeUnit.DAYS)
}.build()
val realEventSource = RealEventSource(request, object : EventSourceListener() {
    override fun onOpen(eventSource: EventSource, response: Response) {
        super.onOpen(eventSource, response)
        showMessage("已连接")
    }

    override fun onEvent(
        eventSource: EventSource,
        id: String?,
        type: String?,
        data: String
    ) {
        super.onEvent(eventSource, id, type, data)
        showMessage(data)
    }

    override fun onClosed(eventSource: EventSource) {
        super.onClosed(eventSource)
        showMessage("已断开")
    }

    override fun onFailure(
        eventSource: EventSource,
        t: Throwable?,
        response: Response?
    ) {
        super.onFailure(eventSource, t, response)
        showMessage("连接失败 ${t?.message}")
    }
})

3.后台消息推送

有了服务端和客户端,我们再实现一个简单的控制台,用于给已连接的客户端推送消息:

<!DOCTYPE html>
<html lang="ch">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Push</title>
</head>
<body>

  <div>
    <h2>Request:</h2>
    <input type="text" id="messageInput">
    <button onclick="sendMessage()">发送消息</button>
  </div>

  <div id="responseContainer">
    <h2>Response:</h2>
    <pre id="responseContent"></pre>
  </div>

  <script>
    function sendMessage() {
      const messageInput = document.getElementById('messageInput');
      const responseContent = document.getElementById('responseContent');

      // 发送 POST 请求到 /push 接口
      fetch('/push', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/x-www-form-urlencoded',
        },
        body: `message=${encodeURIComponent(messageInput.value)}`,
      })
      .then(response => response.text())
      .then(data => {
        // 更新页面上的响应内容
        responseContent.textContent = data;
      })
      .catch(error => {
        console.error('Error:', error);
        responseContent.textContent = 'An error occurred.';
      });
    }
  </script>

</body>
</html>

看下效果:

SSE消息推送

不专业的简单测试了下,并发1万个客户端连接,服务端性能并没有什么明细波动,确实比较轻量级。

4.写在最后

GitHub地址:https://github.com/alidili/SSEDemo

到这里,Android消息推送SSE方案就介绍完了,如有问题可以给我留言评论或者在GitHub中提交Issues,谢谢!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1409893.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Bank_Code_FullName_2020.06.16.xlsx

Bank_Code_FullName_2020.06.16.xlsx 银行联行号和全称 https://download.csdn.net/download/spencer_tseng/88780566 144692条记录&#xff0c;没法子贴上去

抖音VR直播:沉浸式体验一键打通360度精彩

随着5G技术的发展&#xff0c;VR直播近年来也逐步进入到大众的视野中&#xff0c;相比于传统直播&#xff0c;VR直播能够提供更加丰富的内容和多样化的互动方式&#xff0c;让观众更有沉浸感和参与感。现如今&#xff0c;抖音平台也上线了VR直播&#xff0c;凭借沉浸式体验和有…

基于 pytorch-openpose 实现 “多目标” 人体姿态估计

前言 还记得上次通过 MediaPipe 估计人体姿态关键点驱动 3D 角色模型&#xff0c;虽然节省了动作 K 帧时间&#xff0c;但是网上还有一种似乎更方便的方法。MagicAnimate 就是其一&#xff0c;说是只要提供一张人物图片和一段动作视频 (舞蹈武术等)&#xff0c;就可以完成图片…

【Kubernetes】深入了解Kubernetes(K8s):现代容器编排的引领者

欢迎来到英杰社区&#xff1a; https://bbs.csdn.net/topics/617804998 欢迎来到阿Q社区&#xff1a; https://bbs.csdn.net/topics/617897397 作者简介&#xff1a; 辭七七&#xff0c;目前大二&#xff0c;正在学习C/C&#xff0c;Java&#xff0c;Python等 作者主页&#xf…

JVM-初始JVM

什么是JVM JVM 全称是 Java Virtual Machine&#xff0c;中文译名 Java虚拟机。JVM 本质上是一个运行在计算机上的程序&#xff0c;他的职责是运行Java字节码文件。 Java源代码执行流程如下&#xff1a; JVM的功能 1 - 解释和运行 2 - 内存管理 3 - 即时编译 解释和运行 解释…

LeetCode.2865. 美丽塔 I

题目 题目链接 分析 闲谈&#xff1a;每次读 LeetCode 的题目描述都要费老大劲&#xff0c;o(╥﹏╥)o 题意&#xff1a;这个其实意思就是以数组的每一位作为最高点&#xff0c;这个点&#xff08;数字&#xff09;左右两边的数字都不能大于这个数字(可以等于)&#xff0c;…

Qt基础-屏蔽qDebug()、qWarning()调试和警告消息

本文讲解Qt如何-屏蔽qDebug()、qWarning()调试和警告消息 在工程文件.pro里面添加 DEFINES QT_NO_WARNING_OUTPUT\ QT_NO_DEBUG_OUTPUT 如果只想Release版本的时候不打印&#xff1a; Release:DEFINES QT_NO_WARNING_OUTPUT\ QT_NO_DEBUG_OUTPUT 这样只是在Release版本…

想要透明拼接屏展现更加效果,视频源是技术活,尤其作为直播背景

随着科技的飞速发展&#xff0c;视频制作和显示技术也在不断进步。透明拼接屏视频作为一种新型的视频形式&#xff0c;在许多场合都得到了广泛的应用。尼伽小编将深入探讨透明拼接屏视频的制作过程、要求、清晰度&#xff0c;以及目前常作为直播背景的优势。 一、透明拼接屏视频…

Make.com的发送邮件功能已经登峰造极

make.com的发送邮件功能已经做到了登峰造极。 我给你个任务&#xff0c;让你发送个新邮件给谁谁&#xff0c;你一定想到SMTP服务器不就行了。 我给你第二个任务&#xff0c;我让你自动回复一个邮件&#xff0c;注意是回复。 做不到了吧&#xff5e;&#xff5e;&#xff01;…

【3万字】modbus简易不简单的教程

&#x1f396;️Modbus简易不简单的教程 文章目录 &#x1f396;️Modbus简易不简单的教程&#x1f3ab;一、简介1.1 Modbus&#xff1a;工业通信的革命1.2 理解标准化通信1.3 Modbus协议的变体 &#x1f380;二、例程引入2.1 示例&#xff1a;使用01功能码读取灯的开关状态2.2…

电商一年挣100w的赚钱模型

现在有多少人还不知道电商具体应该怎么干&#xff0c;有多少人还是看了身边的朋友做电商挣钱了也跟着做了。然后做半天没做起来&#xff0c;然后就找各种原因&#xff0c;你看别人每天上架你也上架&#xff0c;别人开车你也开车&#xff0c;别人亏钱你也亏钱&#xff0c;别人赚…

dns被劫持怎么修复?6种常用修复方法解读

当遇到DNS被劫持的情况时&#xff0c;通常表现出来的症状是无法正常访问某些网站&#xff0c;或者访问被重定向到不正确的地址。DNS劫持可能是由于恶意软件、黑客活动或者ISP&#xff08;Internet服务提供商&#xff09;的问题导致的。 以下是修复DNS劫持的六种方法&#xff1…

Siamese network 孪生神经网络--一个简单神奇的结构

1.名字的由来 Siamese和Chinese有点像。Siam是古时候泰国的称呼&#xff0c;中文译作暹罗。Siamese也就是“暹罗”人或“泰国”人。Siamese在英语中是“孪生”、“连体”的意思&#xff0c;这是为什么呢&#xff1f; 十九世纪泰国出生了一对连体婴儿&#xff0c;当时的医学技术…

C# 实现 Word 加盖骑缝章效果

目录 实现效果 范例运行环境 Office DCOM 配置 设计实现 创建stamp图章类 电子章图片的计算与定位 旋转图片方法 总结 实现效果 在OA的自动化处理系统中&#xff0c;通过审批的最终节点&#xff0c;可能会对WORD文件加盖电子章&#xff0c;比如定位带有指定文字的Ra…

微软人工智能办公AI工具 Copilot Pro 11项 Copilot 功能

Copilot&#xff08;曾用名 Bing Chat 和 Bing Chat Enterprise&#xff09;在此期间成为了许多用户的日常AI伴侣&#xff0c;并在正式发布后将继续为用户提供AI驱动的网络聊天体验。 微软Copilot官方网址链接&#xff1a;Microsoft Copilot: 你的日常 AI 助手 Copilot详情&am…

密码强度效果

文章目录 一、第一种规则实现 总结如有启发&#xff0c;可点赞收藏哟~ 一、第一种 规则 先展示效果 具体规则 长度显最小8位需有字母大小写需有数字需有特殊字符&#xff08;暂无限制字符类型&#xff09; 实现 定义组件password-strength.vue <template><div …

Github 2024-01-24开源项目日报 Top10

根据Github Trendings的统计&#xff0c;今日(2024-01-24统计)共有10个项目上榜。根据开发语言中项目的数量&#xff0c;汇总情况如下&#xff1a; 开发语言项目数量TypeScript项目3Dart项目2非开发语言项目2Go项目1Rust项目1Shell项目1Dockerfile项目1Jupyter Notebook项目1J…

最佳的reCAPTCHA v2验证码解析器,使用API或扩展自动解析reCAPTCHA v2

最佳的reCAPTCHA v2验证码解析器&#xff0c;使用API或扩展自动解析reCAPTCHA v2 reCAPTCHA v2提出了一个严峻的挑战&#xff0c;需要先进的解决方案。在本文中&#xff0c;我们揭示了验证码解析技术的巅峰&#xff1a;Capsolver。这个卓越的解决方案涵盖了解决reCAPTCHA v2挑战…

2021-01-25

不积跬步无以至千里&#xff0c;不积小流无以成江河&#xff0c;和自己的昨天比&#xff0c;而不是和别人去比。 今日安排&#xff1a; 1.做3道算法题 2.看微信公众号博客&#xff0c;了解技术 //使用callablefuturetask来 获取异步线程的执行结果 写一个类实现callable接…

eNSP学习——交换机配置Trunk接口

目录 原理概述 实验内容 实验目的 实验步骤 实验拓扑 实验编址&#xff1a; 试验步骤 基本配置 创建VLAN&#xff0c;配置Access接口 配置Trunk接口 思考题 原理概述 在以太网中&#xff0c;通过划分VLAN来隔离广播域和增强网络通信的安全性。以太网通常由多台交换机组…