@microsoft/fetch-event-source 实现SSE流式传输

3,437 阅读2分钟

@microsoft/fetch-event-source

@microsoft/fetch-event-source,是微软开发的一个库,用于通过 Fetch API 实现 SSE 的流式数据传输。它封装了请求发送、消息接收和连接恢复的逻辑,非常适合流式数据的处理。

主要参数:

  • method: HTTP 方法,通常为 POST
  • headers: 请求头信息,通常需要指定 Content-Type 为 application/json
  • body: 请求体内容,可以根据需求传递给后端。
  • onmessage: 处理流式消息的回调函数,每当服务器发送一条消息时会调用。
  • onclose: 服务器关闭连接时的回调。
  • onerror: 出现错误时的回调。

安装库:npm install @microsoft/fetch-event-source

客户端

import React, { FC, useEffect, useState } from 'react';
import { fetchEventSource } from '@microsoft/fetch-event-source';

cosnt App =()=>{
    const [data, serData] = useState([]);
   
   const fun = ()=>{
       fetchEventSource('/api/sse',{
           method:"POST",
           headers: { 'Content-Type': 'application/json', },
           body: JSON.stringify({ query: '参数传递' }),
           
           onmessage(event){
               // 这里可以根据接收到的流式数据更新到界面需要的地方
               setData(prevData => [...prevData, JSON.parse(res.data)]);
           },
           
           //  报错
           onerror(err) {
               // 报错信息
                console.error('Error:', err);
            },
           
           // 服务器关闭连接
           onclose() {
                console.log('服务器关闭连接');
           },
       });
   };
    
    return<>
            <div style={{width: '300px', height: '100px', overFlow: 'scroll'}}> 
            {data.map(item => ( <div>{item.name}</div> ))} </div>
    </>
};

服务端

const Koa = require('koa');
const Router = require('koa-router');
const { PassThrough } = require('stream')

//路径管理
const path = require('path');

const static = require('koa-static');
const main = static(path.join(__dirname) + '/www/');

const app = new Koa();
const router = new Router();

app.use(main)

// 发送消息
const sendMessage = async (stream) => {
  const data = [
    {
      name: 'Page A',
      uv: 4000,
      pv: 2400,
      amt: 2400,
    },
    {
      name: 'Page B',
      uv: 3000,
      pv: 1398,
      amt: 2210,
    },
    {
      name: 'Page C',
      uv: 2000,
      pv: 9800,
      amt: 2290,
    },
    {
      name: 'Page D',
      uv: 2780,
      pv: 3908,
      amt: 2000,
    },
    {
      name: 'Page E',
      uv: 1890,
      pv: 4800,
      amt: 2181,
    },
    {
      name: 'Page F',
      uv: 2390,
      pv: 3800,
      amt: 2500,
    },
    {
      name: 'Page G',
      uv: 3490,
      pv: 4300,
      amt: 2100,
    },
  ];

  // 循环上面数组: 推送数据、休眠 2 秒
    for (const value of data) {
        stream.write('data: ' + JSON.stringify(value) + '\n\n');; // 写入数据(推送数据)
        await new Promise((resolve) => setTimeout(resolve, 2000));
    };
};


// SSE 路由处理
router.get('/api/sse', async (ctx, next) => {
     // 设置响应头
     ctx.set({
      'Content-Type': 'text/event-stream',
      'Cache-Control': 'no-cache',
      'Connection': 'keep-alive'
  });

 // 2. 创建流、并作为接口数据进行返回
 const stream = new PassThrough();
 ctx.body = stream;
 ctx.status = 200;

 // 3. 推送流数据
 sendMessage(stream, ctx);
});

app.use(router.routes()).use(router.allowedMethods());

app.listen(3005, () => {
    console.log('Server is running on http://localhost:3005');
});