服务器推送数据你还在用 WebSocket么?

当涉及到推送数据时,人们首先会想到 WebSocket。

的确,WebSocket 允许双向通信,可以自然地用于服务器到浏览器的消息推送。

然而,如果只需要单向的消息推送,HTTP 通过服务器发送的事件也有这种功能。

WebSocket 的通信过程如下:

首先,通过 HTTP 切换协议。服务器返回 101 状态码后,协议切换成功。

然后,开始以 WebSocket 格式的数据通信,任意一方都可以随时向另一方推送消息。

至于 HTTP 中的服务器发送的事件:

服务器返回的 Content-Typetext/event-stream,这是一种可以多次返回内容的流。

服务器发送的事件通过这种类型的消息随时推送数据。

你可能是第一次听说 SSE,但你已经使用过基于它的应用程序。

例如,你使用的 CI/CD 平台会实时打印日志。

那么它如何实时传输构建日志呢?

它需要分次传输,SSE 通常用于以这种方式推送数据。

另一个例子是 ChatGPT。它在回答问题时不会一次给你所有答案,而是逐步分块加载。

这也是基于 SSE 的。

现在我们已经知道 SSE 是什么以及它的应用,让我们自己实现它。

创建一个 Nest 项目。

npx nest new sse-test

运行它:

访问 http://localhost:3000 会显示“Hello World”,表示服务器运行成功。

然后在 AppController 中添加一个流接口。

这里没有用 @Get@Post 等装饰器进行标识,而是 @Sse 装饰器表示这是一个事件流类型的接口。

@Sse('stream')
stream() {
    return new Observable((observer) => {
      observer.next({ data: { msg: 'aaa'} });

      setTimeout(() => {
        observer.next({ data: { msg: 'bbb'} });
      }, 2000);

      setTimeout(() => {
        observer.next({ data: { msg: 'ccc'} });
      }, 5000);
    });
}

返回的是 Observable 对象,然后在内部使用 observer.next 返回消息。可以返回任何 JSON 数据。我们首先返回 aaa,2 秒后返回 bbb,5 秒后返回 ccc。然后创建一个前端页面:创建一个 React 项目。

npx create-react-app --template=typescript sse-test-frontend

App.tsx 中编写以下代码:

import { useEffect } from 'react';

function App() {

  useEffect(() => {
    const eventSource = new EventSource('http://localhost:3000/stream');
    eventSource.onmessage = ({ data }) => {
      console.log('New message', JSON.parse(data));
    };
  }, []);

  return (
    <div>hello</div>
  );
}

export default App;

这个 EventSource 是浏览器的原生 API,用于获取 SSE 接口的响应。它会将每个消息传入回调函数 onmessage 中。

我们在 Nest 服务中启用跨域支持。

然后删除 react 项目中的 index.tsx 文件中的这几行代码,因为它们会导致额外的渲染:

执行 npm run start

因为 3000 端口被占用,它将在 3001 上运行:

访问浏览器:

看到响应了吗?

这就是服务器发送的事件。

devtools 中,你可以看到响应的 Content-Typetext/event-stream

然后在 EventStream 中,你可以看到接收到的每条消息。

通过这种方式,服务器可以随时向网页推送消息。

它的兼容性如何?

你可以在 MDN 上看到。

除了 IE 和 Edge 外,与其他浏览器没有兼容问题。

一般来说,安全使用。

它可以在哪里使用?

服务器发送的事件 特别适合只需要服务器端推送的场景。

例如日志的实时推送。

让我们测试一下:

“tail -f”命令允许你实时查看文件的最新内容。

我们使用 child_process 模块的 exec 函数来执行这个命令,然后监听它的 stdout 输出。

const { exec } = require("child_process");

const childProcess = exec('tail -f ./log');

childProcess.stdout.on('data', (msg) => {
    console.log(msg);
});

使用 node 执行它。

然后添加一个 SSE 接口。

@Sse('stream2')
stream2() {
const childProcess = exec('tail -f ./log');

return new Observable((observer) => {
  childProcess.stdout.on('data', (msg) => {
    observer.next({ data: { msg: msg.toString() }});
  })  
});

检测到新数据后,返回到浏览器。

浏览器连接到这个新接口:

测试如下:

可以看到浏览器已经接收到实时日志。

许多构建日志都是通过 SSE 实时推送的。

日志和类似的东西只是文本,但是如果是二进制数据呢?

在 Node.js 中,二进制数据存储在 Buffer 中。

const { readFileSync } = require("fs");

const buffer = readFileSync('./package.json');

console.log(buffer); 

Buffer 有一个 toJSON 方法:

这可以通过 SSE 接口返回吗?

试一下:

@Sse('stream3')  
stream3() {
    return new Observable((observer) => {
        const json = readFileSync('./package.json').toJSON();
        observer.next({ data: { msg: json }});
    });
}

的确可以。

换句话说,基于 SSE,除了可以推送文本,还可以推送任何二进制数据。

概括

可以使用 WebSocket 或 HTTP 的服务器发送事件(SSE)从服务器推送实时数据。

通过在 HTTP 响应中返回一个 Content-Type 为 text/event-stream 的头,可以通过流多次发送消息。

传输的内容是 JSON 格式,可以用来传输文本或二进制内容。

我们使用 Nest 实现了 SSE 接口。方法使用 @Sse 装饰器进行注释,它返回一个 Observable 对象。可以使用 observer.next 随时返回数据。

在前端,使用 EventSource 的 onmessage 来接收消息。

这个 API 在除 IE 和 Edge 外的其他浏览器有很好的兼容性,可以安全使用。

它有各种应用,如内部消息传递、构建日志的实时显示和 chatgpt 的消息响应。

当遇到需要消息推送的场景时,考虑使用服务器发送的事件而不是 WebSocket。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

rust获取本地ip地址的方法

大家好&#xff0c;我是get_local_info作者带剑书生&#xff0c;这里用一篇文章讲解get_local_info的使用。 get_local_info是什么&#xff1f; get_local_info是一个获取linux系统信息的rust三方库&#xff0c;并提供一些常用功能&#xff0c;目前版本0.2.4。详细介绍地址&a…

直接写一区! ZOA-PCNN-AT-SVM斑马优化并行卷积-支持向量机融合注意力机制的故障识别程序,特征可视化,实验多!图多!

适用平台&#xff1a;Matlab2023版本及以上 本原创程序提出的ZOA-PCNN-AT-SVM故障识别模型还没有人写&#xff01;在此基础上进一步对参考模型进行多重改进&#xff0c;程序注释清晰&#xff0c;干货满满&#xff0c;下面对文章和程序做简要介绍&#xff01; ①识别模型部分参…

计算机导论10-软件与软件工程

文章目录 软件软件的概念软件的定义软件的特征 软件的保护与授权软件的法律保护软件许可 软件工程软件危机软件危机的概念产生软件危机的原因 软件工程的概念软件工程的定义软件工程基本原理软件工程框架软件工程三要素 软件工程方法学软件工程方法软件工程工具软件工程过程 软…

【RPC】网络通信:哪种网络IO模型最适合RPC框架?

一、背景 RPC是解决进程间通信的一种方式。一次RPC调用&#xff0c;本质就是服务消费者与服务提供者间的一次网络信息交换的过程。服务调用者通过网络IO发送一条请求消息&#xff0c;服务提供者接收并解析&#xff0c;处理完相关的业务逻辑之后&#xff0c;再发送一条响应消息…

AttributeError: module ‘openai‘ has no attribute ‘error‘解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

Flink实战之运行架构

本文章&#xff1a;重点是分析清楚运行架构以及并行度与slot的分配 1、JobManager和TaskManager Flink中的节点可以分为JobManager和TaskManager。 JobManager处理器也称为Master&#xff0c;用于协调分布式任务执行。他们用来调度task进行具体的任务。TaskManager处理器也称…

海思SD3403,SS928/926,hi3519dv500,hi3516dv500移植yolov7,yolov8(9)

上一节yolov8的训练已经完成了,现在要开始做模型的转换了,这里和yolov7方式相似,但是有一些差异,尤其是yolov7的不带NMS部分的输出顺序和yolov8的输出顺序与格式是有差异的。 首先还是要自己手动加入rpn_op,这里包含了filter,sort,nms部分。 我们一个一个看,首先filter.py…

从零开始的源码搭建:详解连锁餐饮行业中的点餐小程序开发

时下&#xff0c;点餐小程序成为了许多餐饮企业引入的一种创新工具&#xff0c;不仅方便了顾客的用餐体验&#xff0c;同时也提高了餐厅的运营效率。本文将详细探讨如何从零开始搭建一个源码&#xff0c;并深入解析连锁餐饮行业中的点餐小程序开发过程。 一、需求分析与规划 在…

运维工具之tmux命令

tmux终端复用器的使用 1.tmux的概念 ​ tmux&#xff0c;“Terminal MultipleXer”,意思是"终端复用器"。是一个可以让人们通过一个窗口操作多个会话的工具&#xff0c;对于经常操作Linux系统的运维人员来说&#xff0c;绝对是一款提高工作效率的利器。 2.tmux能帮…

计算机网络 应用层

文章目录 应用层域名系统 DNS域名系统概述互联网的域名结构域名服务器 文件传送协议FTP 概述FTP 的基本工作原理简单文件传送协议 TFTP 远程终端协议 TELNET万维网 WWW统一资源定位符 URL超文本传送协议 HTTP万维网的信息检索系统 电子邮件电子邮件概述简单邮件传送协议 SMTP邮…

微服务基础设施怎么建设,如何选择微服务框架

微服务基础设施架构全貌 微服务 vs SOA 微服务基础设施优先级 微服务框架核心 模式1-嵌入式SDK式 【优点】 1. 架构简单&#xff0c;天然支持高性能、高可用&#xff1b; 2. 维护简单&#xff0c;无需维护独立的 Proxy 节点。 【缺点】 1. 应用侵入&#xff0c;需要集成 SD…

Leetcode2645. 构造有效字符串的最少插入数

Every day a Leetcode 题目来源&#xff1a;2645. 构造有效字符串的最少插入数 解法1&#xff1a;枚举 数学 word 仅由字母 “a”、“b” 和 “c” 组成。 因此我们只需要每次统计相邻字符之间的编号差再减去 1&#xff08;并进行一定修正&#xff09;&#xff0c;就可以得…

CAN 节点状态转换

CAN节点 按照错误严重程度可分为三种不同的状态 主动错误状态&#xff08;Error Active&#xff09; 被动错误状态&#xff08;Error Passive&#xff09; 总线关闭状态&#xff08;Bus Off&#xff09; 存在两种错误计数器 发送错误计数值 TEC : Transmit Error Counter …

Js-web APIs(一)

目录 Web API 基本认知 • 作用和分类 • 什么是DOM • DOM树 • DOM对象(重要) 获取DOM对象 • 根据CSS选择器来获取DOM元素 (重点) 1.选择匹配的第一个元素 2.选择匹配的多个元素 • 其他获取DOM元素方法&#xff08;了解&#xff09; 操作元素内容 • 对象.innerT…

WPF应用程序生存期以及相关事件

WPF 应用程序的生存期会通过 Application 引发的几个事件来加以标记&#xff0c;相关事件对应着应用程序何时启动、激活、停用和关闭。 应用程序生存期事件 • 独立应用程序(传统风格的 Windows 应用程序&#xff0c;这些应用程序作为要安装到客户端计算机并从客户端计算机运…

数据结构与算法教程,数据结构C语言版教程!(第四部分、字符串,数据结构中的串存储结构)三

第四部分、字符串&#xff0c;数据结构中的串存储结构 串存储结构&#xff0c;也就是存储字符串的数据结构。 很明显&#xff0c;字符串之间的逻辑关系也是“一对一”&#xff0c;用线性表的思维不难想出&#xff0c;串存储结构也有顺序存储和链式存储。 提到字符串&#xff…

力扣刷MySQL-第二弹(详细解析)

&#x1f389;欢迎您来到我的MySQL基础复习专栏 ☆* o(≧▽≦)o *☆哈喽~我是小小恶斯法克&#x1f379; ✨博客主页&#xff1a;小小恶斯法克的博客 &#x1f388;该系列文章专栏&#xff1a;力扣刷题讲解-MySQL &#x1f379;文章作者技术和水平很有限&#xff0c;如果文中出…

IP定位技术在网络安全行业的探索

随着互联网的普及和深入生活&#xff0c;网络安全问题日益受到人们的关注。作为网络安全领域的重要技术&#xff0c;IP定位技术正逐渐成为行业研究的热点。本文将深入探讨IP定位技术在网络安全行业的应用和探索。 一、IP定位技术的概述 IP定位技术是通过IP地址来确定设备地理位…

FRE123|开源! 普通人如何快速免费搭建个性化导航网站

FRE123 - Free Resource for Everyone&#xff1a;老胡信息周刊的衍生项目&#xff0c;核心目的是用技术打破信息差&#xff0c;为每个人提供免费优质资源。 老胡的信息周刊在第三个年头&#xff0c;希望这个系列也能持续更新下去&#xff1a; 01.FRE123|老胡周刊免费资源之启动…

什么是防火墙?

目录 什么是防火墙&#xff0c;为什么需要防火墙&#xff1f;防火墙与交换机、路由器对比防火墙和路由器实现安全控制的区别防火墙的发展史1989年至1994年1995年至2004年2005年至今 什么是防火墙&#xff0c;为什么需要防火墙&#xff1f; “防火墙”一词起源于建筑领域&#x…