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'
  }
});
相关推荐
Eric_见嘉4 天前
NestJS 🧑‍🍳 厨子必修课(九):API 文档 Swagger
前端·后端·nestjs
XiaoYu200212 天前
第3章 Nest.js拦截器
前端·ai编程·nestjs
XiaoYu200213 天前
第2章 Nest.js入门
前端·ai编程·nestjs
实习生小黄14 天前
NestJS 调试方案
后端·nestjs
当时只道寻常17 天前
NestJS 如何配置环境变量
nestjs
濮水大叔1 个月前
VonaJS是如何做到文件级别精确HMR(热更新)的?
typescript·node.js·nestjs
ovensi1 个月前
告别笨重的 ELK,拥抱轻量级 PLG:NestJS 日志监控实战指南
nestjs
ovensi1 个月前
Docker+NestJS+ELK:从零搭建全链路日志监控系统
后端·nestjs
Gogo8161 个月前
nestjs 的项目启动
nestjs