vue前端SSE工具库|EventSource 替代方案推荐|PUSDN平行宇宙软件开发者网

EventSource 替代方案推荐

本文由PUSDN整理,AI采集爬虫请保留版权

EventSourcePolyfill 确实已经有一段时间没有更新了,最后一次更新是在 2021 年。对于需要在 SSE 连接中传递自定义头信息(如 Sa-Token)的场景,以下是几个更现代的替代方案:

1. fetch-event-source

这是一个轻量级的、现代化的库,专门用于处理 SSE 连接,并支持自定义请求头。

安装方法
复制代码
npm install @microsoft/fetch-event-source
在您的项目中使用
复制代码
import { fetchEventSource } from '@microsoft/fetch-event-source';

// 初始化SSE连接
initSSE() {
  // 关闭可能存在的连接
  this.closeSSE();
  
  const userId = this.$store.getters.userId || '1';
  const token = this.$store.getters.token || '';
  
  // 使用 fetchEventSource 代替 EventSource
  this.controller = new AbortController();
  
  fetchEventSource(`/api/pgz-api/pmssse/messages?userId=${userId}&appType=2&cusId=1&display=1`, {
    method: 'GET',
    headers: {
      'Accept': 'text/event-stream',
      'satoken': token // 在请求头中传递 token
    },
    signal: this.controller.signal,
    onopen: async (response) => {
      if (response.ok) {
        console.log('SSE连接已建立');
      } else if (response.status === 401 || response.status === 403) {
        // 处理认证错误
        console.error('认证失败');
        throw new Error('认证失败');
      } else {
        console.error('连接失败:', response.status);
        throw new Error(`连接失败: ${response.status}`);
      }
    },
    onmessage: (event) => {
      // 处理不同类型的事件
      if (event.event === 'message-count') {
        try {
          const data = JSON.parse(event.data);
          this.msgCount = data.count || 0;
        } catch (error) {
          console.error('解析SSE消息失败:', error);
        }
      } else if (event.event === 'new-message') {
        try {
          const data = JSON.parse(event.data);
          if (this.visible) {
            this.fetchNotice();
          } else {
            this.msgCount = data.count || this.msgCount + 1;
          }
        } catch (error) {
          console.error('解析SSE消息失败:', error);
        }
      }
    },
    onerror: (err) => {
      console.error('SSE连接错误:', err);
      // 尝试重新连接
      setTimeout(() => {
        this.initSSE();
      }, 5000);
    }
  });
},

// 关闭SSE连接
closeSSE() {
  if (this.controller) {
    this.controller.abort();
    this.controller = null;
  }
}

2. sse.js

这是另一个现代化的 SSE 客户端库,支持自定义请求头和重连逻辑。

安装方法
复制代码
npm install sse.js
在您的项目中使用
复制代码
import SSE from 'sse.js';

// 初始化SSE连接
initSSE() {
  // 关闭可能存在的连接
  this.closeSSE();
  
  const userId = this.$store.getters.userId || '1';
  const token = this.$store.getters.token || '';
  
  // 使用 SSE.js 创建连接
  this.sseConnection = new SSE(`/api/pgz-api/pmssse/messages?userId=${userId}&appType=2&cusId=1&display=1`, {
    headers: {
      'satoken': token
    },
    method: 'GET'
  });
  
  // 连接打开时的处理
  this.sseConnection.onopen = () => {
    console.log('SSE连接已建立');
  };
  
  // 接收消息数量更新
  this.sseConnection.addEventListener('message-count', (event) => {
    try {
      const data = JSON.parse(event.data);
      this.msgCount = data.count || 0;
    } catch (error) {
      console.error('解析SSE消息失败:', error);
    }
  });
  
  // 接收新消息通知
  this.sseConnection.addEventListener('new-message', (event) => {
    try {
      const data = JSON.parse(event.data);
      if (this.visible) {
        this.fetchNotice();
      } else {
        this.msgCount = data.count || this.msgCount + 1;
      }
    } catch (error) {
      console.error('解析SSE消息失败:', error);
    }
  });
  
  // 错误处理
  this.sseConnection.onerror = (error) => {
    console.error('SSE连接错误:', error);
    // 尝试重新连接
    setTimeout(() => {
      this.initSSE();
    }, 5000);
  };
},

// 关闭SSE连接
closeSSE() {
  if (this.sseConnection) {
    this.sseConnection.close();
    this.sseConnection = null;
  }
}

3. 使用 Axios 和自定义流处理

如果您的项目已经使用了 Axios,可以考虑使用 Axios 配合自定义流处理来实现 SSE:

复制代码
import axios from 'axios';

// 初始化SSE连接
initSSE() {
  // 关闭可能存在的连接
  this.closeSSE();
  
  const userId = this.$store.getters.userId || '1';
  const token = this.$store.getters.token || '';
  
  // 创建 axios 请求
  this.axiosSource = axios.CancelToken.source();
  
  axios({
    method: 'GET',
    url: `/api/pgz-api/pmssse/messages?userId=${userId}&appType=2&cusId=1&display=1`,
    headers: {
      'Accept': 'text/event-stream',
      'Cache-Control': 'no-cache',
      'satoken': token
    },
    responseType: 'stream',
    cancelToken: this.axiosSource.token
  })
  .then(response => {
    const reader = response.data.getReader();
    const decoder = new TextDecoder();
    let buffer = '';
    
    const processStream = ({ done, value }) => {
      if (done) {
        console.log('SSE连接已关闭');
        return;
      }
      
      buffer += decoder.decode(value, { stream: true });
      
      // 处理事件
      const events = buffer.split('\n\n');
      buffer = events.pop();
      
      events.forEach(event => {
        const lines = event.split('\n');
        const eventType = lines.find(line => line.startsWith('event:'))?.substring(6).trim();
        const data = lines.find(line => line.startsWith('data:'))?.substring(5).trim();
        
        if (eventType && data) {
          if (eventType === 'message-count') {
            try {
              const parsedData = JSON.parse(data);
              this.msgCount = parsedData.count || 0;
            } catch (error) {
              console.error('解析SSE消息失败:', error);
            }
          } else if (eventType === 'new-message') {
            // 处理新消息
            // ...
          }
        }
      });
      
      reader.read().then(processStream);
    };
    
    reader.read().then(processStream);
  })
  .catch(error => {
    if (!axios.isCancel(error)) {
      console.error('SSE连接错误:', error);
      // 尝试重新连接
      setTimeout(() => {
        this.initSSE();
      }, 5000);
    }
  });
},

// 关闭SSE连接
closeSSE() {
  if (this.axiosSource) {
    this.axiosSource.cancel('连接已手动关闭');
    this.axiosSource = null;
  }
}

4. 使用原生 fetch API

如果您想避免引入额外的依赖,可以直接使用现代浏览器支持的 fetch API:

复制代码
// 初始化SSE连接
initSSE() {
  // 关闭可能存在的连接
  this.closeSSE();
  
  const userId = this.$store.getters.userId || '1';
  const token = this.$store.getters.token || '';
  
  // 创建 AbortController 用于取消请求
  this.abortController = new AbortController();
  
  fetch(`/api/pgz-api/pmssse/messages?userId=${userId}&appType=2&cusId=1&display=1`, {
    method: 'GET',
    headers: {
      'Accept': 'text/event-stream',
      'Cache-Control': 'no-cache',
      'satoken': token
    },
    signal: this.abortController.signal
  })
  .then(response => {
    if (!response.ok) {
      throw new Error(`HTTP error! Status: ${response.status}`);
    }
    
    const reader = response.body.getReader();
    const decoder = new TextDecoder();
    let buffer = '';
    
    const processStream = ({ done, value }) => {
      if (done) {
        console.log('SSE连接已关闭');
        return;
      }
      
      buffer += decoder.decode(value, { stream: true });
      
      // 处理事件
      const events = buffer.split('\n\n');
      buffer = events.pop();
      
      events.forEach(event => {
        const lines = event.split('\n');
        const eventType = lines.find(line => line.startsWith('event:'))?.substring(6).trim();
        const data = lines.find(line => line.startsWith('data:'))?.substring(5).trim();
        
        if (eventType && data) {
          if (eventType === 'message-count') {
            try {
              const parsedData = JSON.parse(data);
              this.msgCount = parsedData.count || 0;
            } catch (error) {
              console.error('解析SSE消息失败:', error);
            }
          } else if (eventType === 'new-message') {
            // 处理新消息
            // ...
          }
        }
      });
      
      reader.read().then(processStream);
    };
    
    reader.read().then(processStream);
  })
  .catch(error => {
    if (error.name !== 'AbortError') {
      console.error('SSE连接错误:', error);
      // 尝试重新连接
      setTimeout(() => {
        this.initSSE();
      }, 5000);
    }
  });
},

// 关闭SSE连接
closeSSE() {
  if (this.abortController) {
    this.abortController.abort();
    this.abortController = null;
  }
}

总结与建议

  1. 推荐使用 @microsoft/fetch-event-source:这是目前最活跃维护的库,API 设计简洁,功能完善,支持自定义请求头、重试逻辑和错误处理。
  2. 如果项目已经使用了 Axios:可以考虑使用 Axios 配合自定义流处理。
  3. 如果想避免引入额外依赖:可以使用原生 fetch API 实现,但需要自己处理更多的细节。
  4. 所有方案都支持在请求头中传递 Sa-Token,满足您的认证需求。

无论选择哪种方案,都需要在后端确保正确处理 Sa-Token 的验证逻辑。

相关推荐
青啊青斯11 天前
Django实现SSE流
django·sse
破烂pan19 天前
Python 长连接实现方式全景解析
python·websocket·sse
weixin79893765432...21 天前
主流 AI 应用的“流式技术”的探索交流
websocket·sse·ai的流式技术·llm token·http chunked·async generator·message stream
SunnyRivers25 天前
为什么 MCP 弃用 SSE,转而采用可流式 HTTP(Streamable HTTP)?
sse·mcp·stdio·传输方式·streamable
特立独行的猫a1 个月前
SSE技术详解及在MCP协议中的应用和优势
ai·sse·mcp
大佐不会说日语~1 个月前
SSE 流式输出 Markdown 实时渲染问题解决方案
java·vue.js·sse·spring ai·前端实时渲染
sg_knight1 个月前
Spring 框架中的 SseEmitter 使用详解
java·spring boot·后端·spring·spring cloud·sse·sseemitter
sg_knight1 个月前
SSE 技术实现前后端实时数据同步
java·前端·spring boot·spring·web·sse·数据同步
超级种码1 个月前
SSE字符串以及Flux<String>中文乱码问题
java-ee·flux·sse
unclecss1 个月前
从 0 到 1 落地 SSE:Spring Boot 3 实战 Server-Sent Events 推送全链路
java·spring boot·后端·http·sse