Angular与Nestjs的文件流传输(SSE)

概述SSE

(Server-Sent Events)是一种用于实现服务器主动向客户端推送数据的技术,也被称为"事件流"(Event Stream)。它基于 HTTP 协议,利用了其长连接特性,在客户端与服务器之间建立一条持久化连接,并通过这条连接实现服务器向客户端的实时数据推送。

实例

使用生成事件的脚本 URL 创建一个 EventSource 对象,用来开启与服务器的连接并从中接收事件。

TS 复制代码
const eventSource = new EventSource(url, configuration);
  • url:一个USVString ,它代表远程资源的位置

  • configuration : 为配置新连接提供选项:

    • withCredentials,默认为 false,指示 CORS 是否应包含凭据 ( credentials )。

属性

eventSource.readyState:只读属性 返回一个表示连接状态的数字

  • 0--- 连接
  • 1- 打开
  • 2--- 关闭

eventSource.url:只读属性 返回一个表示源 URL 的字符串。

eventSource.withCredentials:只读属性 返回一个布尔值,指示该EventSource对象是否是使用 CORS 凭据集实例化的。

方法

当通过事件源接收到数据时,将触发 APImessage的事件

Ts 复制代码
interface MessageEvent{
data:string,//消息发送器发送的数据。
origin,//表示消息发射器来源的字符串。
lastEventId,//表示事件的唯一 ID 的字符串。
source,//代表消息发射器的A `MessageEventSource`(可以是WindowProxy、MessagePort)或对象ServiceWorker
ports//表示与发送消息的通道关联的端口的对象数组(在适当的情况下,例如在通道消息传递中或向共享工作线程发送消息时)。
}

evtSource.onmessage = function (event:MessageEvent) {}

当打开与事件源的连接时,将触发 APIopen的事件

javascript 复制代码
evtSource.addEventListener("open", (e) => {
  console.log("The connection has been established.");
});

当与事件源的连接无法打开时,会触发 APIerror的事件

Ts 复制代码
//当发生错误时(例如网络超时或与访问控制有关的问题),会生成一个错误事件。
evtSource.onerror = (err) => {
  console.error("EventSource failed:", err);
};

该接口close() 的方法EventSource 会关闭连接(如果已建立),并将属性设置 EventSource.readyState2(关闭)。

Ts 复制代码
//关闭事件流
//默认情况下,如果客户端和服务器之间的连接关闭,则连接将重新启动。
evtSource.close();

nestjs后端

今天公司有一个新的需求就是将一个40M的json文件发送到前端中去,这时就可以使用SSE进行流传输了,切片+压缩+流传输 搞定!!!

Ts 复制代码
  sseV2(@Res() res: FastifyReply): Observable<MessageEvent> {
    const faguiJson = join(process.cwd(), './src/xiaoxiao.json');//数据就是一个普通的json数据
    const readJson = fs.readFileSync(faguiJson, 'utf-8');
    const jsonData = JSON.parse(readJson);
    const eventChunks = jsonData.data;

    const chunkSize = 1; // 每次发送的数据块大小
    
    //要是有更好的方案 各位掘友们一定要提点提点我丫 我实在是想不出更快的方案了
    return interval(0).pipe(
      take(Math.ceil(eventChunks.length / chunkSize)),
      map((index) => {
        const start = index * chunkSize;
        const end = Math.min(start + chunkSize, eventChunks.length);
        const chunk = eventChunks.slice(start, end);

        const compressedData = pako.gzip(JSON.stringify(chunk));
        const base64Data = Buffer.from(compressedData).toString('base64');

        return {
          data: base64Data,
        };
      }),
    );
  }

Angular前端

刚开始用angular是实在不适应(而且国内文档教程极其少)但用着用着还真香了,当然了要是搭建一个小项目用vue就足够了,angular还是比较适合大型项目

这里我就直接贴代码了

Ts 复制代码
private eventSource!: EventSource;
  constructor( private ngZone: NgZone) {}
  ngOnInit(): void {
    this.eventSource = new EventSource('/api/item/sseV2');
    this.eventSource.onmessage = (event) => {
      const base64EncodedData = event.data;
      
      // 将base64编码的数据转换成原始的压缩数据
      const compressedData = new Uint8Array(
        atob(base64EncodedData)
          .split('')
          .map((char) => char.charCodeAt(0))
      );

      // 对压缩数据进行解压缩处理
      const data = JSON.parse(pako.ungzip(compressedData, { to: 'string' }));
      //这里有个坑 如果不提醒视图需要更新的话是不会分段加载数据的 
      // 有没有大佬能指点下 有没有更好的方案 让视图更新
      this.ngZone.run(() => {
        this.receivedData.push(...data);
      });
    };
    this.eventSource.onerror = (error) => {
      console.log(error);
      console.log('An error occurred while attempting to connect.');
      this.eventSource.close();
    };
  }

当然还是有一个问题,EventSource不支持传入headers,也就无法传给服务端token。这时候 EventSourcePolyfill就来了

Ts 复制代码
var es = new EventSourcePolyfill('/events', {
  headers: {//设置你所需要的header
    'X-Custom-Header': 'value'
  }
});
相关推荐
webxue2 天前
NestJS配置环境变量、读取Yaml配置的保姆级教程
node.js·nestjs
超级无敌暴龙兽5 天前
微服务架构的基础与实践:构建灵活的分布式系统
微服务·node.js·nestjs
寻找奶酪的mouse6 天前
【NestJS全栈之旅】应用篇:通用爬虫服务三两事儿
前端·后端·nestjs
_jiang8 天前
nestjs 入门实战最强篇
redis·typescript·nestjs
敲代码的彭于晏11 天前
【Nest.js 10】JWT+Redis实现登录互踢
前端·后端·nestjs
前端小王hs25 天前
Nest通用工具函数执行顺序
javascript·后端·nestjs
明远湖之鱼1 个月前
从入门到入门学习NestJS
前端·后端·nestjs
吃葡萄不吐番茄皮1 个月前
从零开始学 NestJS(一):为什么要学习 Nest
前端·nestjs
东方小月1 个月前
Vue3+NestJS实现权限管理系统(六):接口按钮权限控制
前端·后端·nestjs
白雾茫茫丶1 个月前
Nest.js 实战 (十四):如何获取客户端真实 IP
nginx·nestjs