更新记录

1.0.0(2025-09-23) 下载此版本

1.第一版本 2.sse使用renderjs+@microsoft/fetch-event-source实现 3.实现打印结果如图


平台兼容性

uni-app(3.7.3)

Vue2 Vue3 Chrome Safari app-vue app-nvue Android iOS 鸿蒙
- - - -
微信小程序 支付宝小程序 抖音小程序 百度小程序 快手小程序 京东小程序 鸿蒙元服务 QQ小程序 飞书小程序 快应用-华为 快应用-联盟
- - - - - - - - - - -

SSE (Server-Sent Events) 功能使用指南

效果展示

img.png img_1.png

目录

  1. 概述
  2. 快速开始
  3. 组件介绍
  4. API 参考
  5. 使用示例
  6. 平台兼容性
  7. 配置说明
  8. 事件处理
  9. 错误处理和重连
  10. 服务器端实现
  11. 故障排除
  12. 最佳实践

概述

本项目集成了强大的 SSE (Server-Sent Events) 功能,支持 H5、Android 和 iOS 平台的实时数据推送。基于 @microsoft/fetch-event-source 库实现,提供了比原生 EventSource 更强大的功能,包括:

  • ✅ 支持 GET 和 POST 请求方法
  • ✅ 灵活的请求头配置
  • ✅ 智能重连机制
  • ✅ 自动降级到原生 EventSource
  • ✅ 完整的错误处理
  • ✅ 跨平台兼容性

快速开始

1. 基础用法

<template>
  <view>
    <!-- SSE 组件 -->
    <uni-sse
      ref="sse"
      url="https://your-server.com/api/sse"
      :headers="{ 'Authorization': `Bearer ${token}` }"
      :autoConnect="true"
      @message="handleMessage"
      @connected="onConnected"
      @error="onError"
    />
  </view>
</template>

<script>
export default {
  data() {
    return {
      token: 'your-auth-token'
    }
  },
  methods: {
    handleMessage(data) {
      console.log('收到SSE消息:', data);
    },
    onConnected() {
      console.log('SSE连接成功');
    },
    onError(error) {
      console.error('SSE连接错误:', error);
    }
  }
}
</script>

2. 手动控制连接

// 手动连接
this.$refs.sse.connect();

// 断开连接
this.$refs.sse.disconnect();

// 重新连接
this.$refs.sse.reconnect();

组件介绍

UniSSE 组件

主要的 SSE 组件,位于 components/uni-sse/uni-sse.vue

核心特性:

  • 使用 renderjs 实现跨平台兼容
  • 基于 fetch-event-source 库
  • 自动重连机制
  • 完整的生命周期管理

SSE 服务管理器

全局服务管理器,位于 utils/sseService.js

功能:

  • 统一的 SSE 连接管理
  • 全局事件派发
  • 单例模式设计

SSE 演示组件

演示和测试组件,位于 components/sse-demo/sse-demo.vue

功能:

  • 实时配置和测试
  • 连接状态显示
  • 消息历史记录

API 参考

UniSSE 组件属性 (Props)

属性名 类型 默认值 必需 说明
url String - SSE 服务器地址
headers Object {} 请求头配置
method String 'GET' HTTP 方法 (GET/POST)
autoConnect Boolean true 是否自动连接
reconnectAttempts Number 5 最大重连次数
reconnectInterval Number 3000 重连间隔 (毫秒)

UniSSE 组件事件

事件名 参数 说明
connected - 连接成功时触发
disconnected - 连接断开时触发
connecting - 开始连接时触发
disconnect - 开始断开时触发
message data 收到消息时触发
error error 发生错误时触发
maxReconnectReached - 达到最大重连次数时触发

UniSSE 组件方法

方法名 参数 返回值 说明
connect() - Boolean 手动建立连接
disconnect() - - 手动断开连接
reconnect() - - 重新连接

SSE 服务管理器 API

import sseService from '@/utils/sseService.js'

// 初始化配置
sseService.init({
  url: 'https://your-server.com/api/sse',
  headers: { 'Authorization': 'Bearer token' },
  autoConnect: true
});

// 设置组件实例
sseService.setInstance(this.$refs.uniSSE);

// 连接/断开
sseService.connect(url, headers);
sseService.disconnect();

// 事件监听
sseService.on('message', (data) => { /* 处理消息 */ });
sseService.off('message', callback);

// 获取状态
const status = sseService.getConnectionStatus();

使用示例

1. 基础 GET 请求

<template>
  <uni-sse
    url="https://api.example.com/sse"
    method="GET"
    :headers="{
      'Authorization': `Bearer ${userToken}`,
      'Accept': 'text/event-stream'
    }"
    @message="handleMessage"
  />
</template>

<script>
export default {
  data() {
    return {
      userToken: 'your-access-token'
    }
  },
  methods: {
    handleMessage(event) {
      const { id, data, type } = event;
      console.log(`消息ID: ${id}, 类型: ${type}, 数据:`, data);
    }
  }
}
</script>

2. POST 请求示例

<template>
  <uni-sse
    url="https://api.example.com/sse"
    method="POST"
    :headers="{
      'Authorization': `Bearer ${userToken}`,
      'Content-Type': 'application/json'
    }"
    @message="handleMessage"
  />
</template>

3. 完整应用示例

<template>
  <view class="app">
    <!-- 连接状态指示器 -->
    <view class="status-bar">
      <text :class="['status', statusClass]">{{ statusText }}</text>
      <button @click="toggleConnection">
        {{ isConnected ? '断开' : '连接' }}
      </button>
    </view>

    <!-- 消息显示区域 -->
    <scroll-view class="messages" scroll-y>
      <view v-for="(msg, index) in messages" :key="index" class="message">
        <text class="time">{{ formatTime(msg.timestamp) }}</text>
        <text class="content">{{ msg.content }}</text>
      </view>
    </scroll-view>

    <!-- SSE 组件 -->
    <uni-sse
      ref="sseClient"
      :url="sseConfig.url"
      :method="sseConfig.method"
      :headers="sseConfig.headers"
      :autoConnect="sseConfig.autoConnect"
      :reconnectAttempts="5"
      :reconnectInterval="3000"
      @connected="onConnected"
      @disconnected="onDisconnected"
      @connecting="onConnecting"
      @message="onMessage"
      @error="onError"
      @maxReconnectReached="onMaxReconnectReached"
    />
  </view>
</template>

<script>
import { mapState } from 'vuex';

export default {
  data() {
    return {
      isConnected: false,
      isConnecting: false,
      messages: [],
      sseConfig: {
        url: '',
        method: 'GET',
        headers: {},
        autoConnect: true
      }
    }
  },

  computed: {
    ...mapState(['userInfo']),

    statusText() {
      if (this.isConnecting) return '连接中...';
      if (this.isConnected) return '已连接';
      return '未连接';
    },

    statusClass() {
      if (this.isConnecting) return 'connecting';
      if (this.isConnected) return 'connected';
      return 'disconnected';
    }
  },

  created() {
    this.initSSEConfig();
  },

  methods: {
    initSSEConfig() {
      this.sseConfig = {
        url: 'https://your-api.com/sse',
        method: 'GET',
        headers: {
          'Authorization': `Bearer ${this.userInfo.accessToken}`,
          'Accept': 'text/event-stream'
        },
        autoConnect: !!this.userInfo.accessToken
      };
    },

    toggleConnection() {
      if (this.isConnected || this.isConnecting) {
        this.$refs.sseClient.disconnect();
      } else {
        this.$refs.sseClient.connect();
      }
    },

    onConnected() {
      this.isConnected = true;
      this.isConnecting = false;
      uni.showToast({ title: '连接成功', icon: 'success' });
    },

    onDisconnected() {
      this.isConnected = false;
      this.isConnecting = false;
    },

    onConnecting() {
      this.isConnecting = true;
    },

    onMessage(event) {
      this.messages.unshift({
        timestamp: Date.now(),
        content: typeof event.data === 'object' 
          ? JSON.stringify(event.data, null, 2) 
          : event.data,
        id: event.id,
        type: event.type
      });

      // 只保留最近 100 条消息
      if (this.messages.length > 100) {
        this.messages = this.messages.slice(0, 100);
      }

      // 处理特定类型的消息
      this.handleBusinessMessage(event.data);
    },

    onError(error) {
      console.error('SSE 错误:', error);
      uni.showToast({
        title: `连接错误: ${error.message}`,
        icon: 'none',
        duration: 3000
      });
    },

    onMaxReconnectReached() {
      uni.showModal({
        title: '连接失败',
        content: '已达到最大重连次数,请检查网络或服务器状态',
        showCancel: false
      });
    },

    handleBusinessMessage(data) {
      if (typeof data === 'object' && data.type) {
        switch (data.type) {
          case 'notification':
            this.showNotification(data);
            break;
          case 'data_update':
            this.updateApplicationData(data);
            break;
          case 'system_alert':
            this.handleSystemAlert(data);
            break;
          default:
            console.log('未知消息类型:', data.type);
        }
      }
    },

    showNotification(data) {
      uni.showToast({
        title: data.title || '新消息',
        icon: 'none',
        duration: 2000
      });
    },

    updateApplicationData(data) {
      // 更新应用数据
      this.$store.dispatch('updateData', data.payload);
    },

    handleSystemAlert(data) {
      uni.showModal({
        title: data.title || '系统通知',
        content: data.message,
        showCancel: false
      });
    },

    formatTime(timestamp) {
      return new Date(timestamp).toLocaleTimeString();
    }
  }
}
</script>

<style scoped>
.app {
  height: 100vh;
  display: flex;
  flex-direction: column;
}

.status-bar {
  padding: 20rpx;
  background: #f5f5f5;
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.status {
  font-size: 28rpx;
  font-weight: bold;
}

.status.connected { color: #52c41a; }
.status.connecting { color: #1890ff; }
.status.disconnected { color: #999; }

.messages {
  flex: 1;
  padding: 20rpx;
}

.message {
  margin-bottom: 20rpx;
  padding: 20rpx;
  background: #fff;
  border-radius: 8rpx;
  box-shadow: 0 2rpx 4rpx rgba(0,0,0,0.1);
}

.time {
  display: block;
  font-size: 24rpx;
  color: #999;
  margin-bottom: 10rpx;
}

.content {
  font-size: 28rpx;
  color: #333;
  white-space: pre-wrap;
}
</style>

平台兼容性

H5 平台

  • ✅ 完整支持 fetch-event-source 功能
  • ✅ 原生 EventSource 降级支持
  • ✅ 所有现代浏览器兼容

APP 平台 (Android/iOS)

  • ✅ 通过 renderjs 运行在 WebView 环境
  • ✅ 支持所有 fetch-event-source 功能
  • ✅ 自动处理平台差异

小程序平台

  • ❌ 不支持(小程序环境限制)
  • 🔄 可以使用 WebSocket 或长轮询替代

配置说明

1. 基础配置

// 最小化配置
{
  url: 'https://your-server.com/sse',
  headers: {
    'Authorization': 'Bearer your-token'
  }
}

2. 完整配置

// 完整配置示例
{
  url: 'https://your-server.com/api/sse',
  method: 'GET', // 或 'POST'
  headers: {
    'Authorization': 'Bearer your-access-token',
    'Content-Type': 'application/json',
    'Accept': 'text/event-stream',
    'Cache-Control': 'no-cache',
    'X-Custom-Header': 'custom-value'
  },
  autoConnect: true,
  reconnectAttempts: 5,
  reconnectInterval: 3000
}

3. 动态配置

// 从配置文件读取
import config from '@/common/config.js';

computed: {
  sseConfig() {
    return {
      url: config.baseURL + config.sseURL,
      headers: {
        'Authorization': `Bearer ${this.userToken}`,
        'Content-Type': 'application/json'
      },
      reconnectAttempts: config.sse?.maxReconnectAttempts || 5,
      reconnectInterval: config.sse?.reconnectInterval || 3000
    };
  }
}

事件处理

1. 消息事件

onMessage(event) {
  const { id, data, type } = event;

  // 检查消息类型
  if (type === 'heartbeat') {
    // 心跳消息,更新连接状态
    this.updateHeartbeat();
    return;
  }

  // 处理业务消息
  if (typeof data === 'object') {
    this.handleStructuredMessage(data);
  } else {
    this.handleTextMessage(data);
  }
}

2. 连接状态事件

// 连接成功
onConnected() {
  console.log('SSE 连接已建立');
  this.connectionStatus = 'connected';

  // 可以发送连接成功的业务逻辑
  this.sendConnectionNotification();
}

// 连接断开
onDisconnected() {
  console.log('SSE 连接已断开');
  this.connectionStatus = 'disconnected';

  // 清理相关状态
  this.clearPendingTasks();
}

// 连接错误
onError(error) {
  console.error('SSE 连接错误:', error);

  // 根据错误类型处理
  if (error.message.includes('401')) {
    // 认证失败,需要重新登录
    this.handleAuthError();
  } else if (error.message.includes('5')) {
    // 服务器错误,显示提示
    this.showServerErrorTip();
  }
}

3. 全局事件监听

// 在 created 钩子中监听全局事件
created() {
  uni.$on('sse-connected', this.onGlobalSSEConnected);
  uni.$on('sse-disconnected', this.onGlobalSSEDisconnected);
  uni.$on('sse-message', this.onGlobalSSEMessage);
},

// 在 beforeDestroy 钩子中移除监听
beforeDestroy() {
  uni.$off('sse-connected', this.onGlobalSSEConnected);
  uni.$off('sse-disconnected', this.onGlobalSSEDisconnected);
  uni.$off('sse-message', this.onGlobalSSEMessage);
},

methods: {
  onGlobalSSEConnected() {
    // 全局 SSE 连接成功处理
  },

  onGlobalSSEMessage(data) {
    // 全局 SSE 消息处理
  }
}

错误处理和重连

1. 错误类型

错误类型 说明 处理策略
网络错误 网络连接问题 自动重连
认证错误 (401/403) Token 失效或权限不足 停止重连,提示重新登录
服务器错误 (5xx) 服务器内部错误 自动重连
客户端错误 (4xx) 请求参数错误 停止重连,检查配置

2. 重连策略

// 重连配置
{
  reconnectAttempts: 5,        // 最大重连次数
  reconnectInterval: 3000,     // 初始重连间隔(毫秒)
  // 实际重连间隔使用指数退避算法:
  // delay = min(interval * 1.5^(attempts-1), 30000)
}

3. 自定义错误处理

onError(error) {
  // 错误分类处理
  const errorHandlers = {
    // 认证错误
    401: () => {
      uni.showModal({
        title: '认证失败',
        content: '登录已过期,请重新登录',
        success: (res) => {
          if (res.confirm) {
            this.redirectToLogin();
          }
        }
      });
    },

    // 权限错误
    403: () => {
      uni.showToast({
        title: '权限不足',
        icon: 'none'
      });
    },

    // 服务器错误
    500: () => {
      uni.showToast({
        title: '服务器错误,正在重试...',
        icon: 'none'
      });
    },

    // 默认错误处理
    default: () => {
      uni.showToast({
        title: `连接错误: ${error.message}`,
        icon: 'none'
      });
    }
  };

  // 提取状态码
  const statusCode = this.extractStatusCode(error.message);
  const handler = errorHandlers[statusCode] || errorHandlers.default;
  handler();
}

服务器端实现

1. Node.js + Express

const express = require('express');
const app = express();

// 启用 CORS
app.use((req, res, next) => {
  res.header('Access-Control-Allow-Origin', '*');
  res.header('Access-Control-Allow-Headers', 'Authorization, Content-Type, Cache-Control');
  res.header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
  next();
});

// SSE 端点
app.get('/api/sse', (req, res) => {
  // 验证认证
  const token = req.headers.authorization?.replace('Bearer ', '');
  if (!token || !isValidToken(token)) {
    return res.status(401).json({ error: 'Unauthorized' });
  }

  // 设置 SSE 响应头
  res.writeHead(200, {
    'Content-Type': 'text/event-stream',
    'Cache-Control': 'no-cache',
    'Connection': 'keep-alive',
    'Access-Control-Allow-Origin': '*'
  });

  // 发送连接确认
  res.write('data: {"type":"connected","message":"SSE连接已建立"}\n\n');

  // 定期发送心跳
  const heartbeat = setInterval(() => {
    res.write('data: {"type":"heartbeat","timestamp":' + Date.now() + '}\n\n');
  }, 30000);

  // 监听业务事件
  const messageHandler = (data) => {
    res.write(`data: ${JSON.stringify(data)}\n\n`);
  };

  // 注册消息监听器(假设使用 EventEmitter)
  eventBus.on('user_message', messageHandler);

  // 客户端断开时清理
  req.on('close', () => {
    clearInterval(heartbeat);
    eventBus.off('user_message', messageHandler);
    console.log('SSE client disconnected');
  });
});

function isValidToken(token) {
  // 实现 token 验证逻辑
  return true; // 示例
}

2. Spring Boot (Java)

@RestController
@RequestMapping("/api")
public class SSEController {

    @GetMapping(value = "/sse", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public ResponseEntity<SseEmitter> streamEvents(
            @RequestHeader("Authorization") String authHeader) {

        // 验证认证
        String token = authHeader.replace("Bearer ", "");
        if (!isValidToken(token)) {
            return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
        }

        SseEmitter emitter = new SseEmitter(Long.MAX_VALUE);

        try {
            // 发送连接确认
            emitter.send(SseEmitter.event()
                .name("connected")
                .data("{\"type\":\"connected\",\"message\":\"SSE连接已建立\"}"));

            // 启动心跳任务
            startHeartbeat(emitter);

            // 注册消息监听器
            registerMessageListener(emitter);

        } catch (IOException e) {
            emitter.completeWithError(e);
        }

        return ResponseEntity.ok(emitter);
    }

    private void startHeartbeat(SseEmitter emitter) {
        ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
        executor.scheduleAtFixedRate(() -> {
            try {
                Map<String, Object> heartbeat = new HashMap<>();
                heartbeat.put("type", "heartbeat");
                heartbeat.put("timestamp", System.currentTimeMillis());

                emitter.send(SseEmitter.event()
                    .name("heartbeat")
                    .data(heartbeat));
            } catch (IOException e) {
                emitter.completeWithError(e);
                executor.shutdown();
            }
        }, 30, 30, TimeUnit.SECONDS);
    }

    private boolean isValidToken(String token) {
        // 实现 token 验证逻辑
        return true; // 示例
    }
}

3. 消息格式规范

// 标准消息格式
{
  "type": "message_type",      // 消息类型
  "id": "unique_message_id",   // 消息唯一标识
  "timestamp": 1640995200000,  // 时间戳
  "data": {                    // 消息数据
    // 业务数据...
  }
}

// 示例消息类型
{
  // 连接确认
  "type": "connected",
  "message": "SSE连接已建立"
}

{
  // 心跳消息
  "type": "heartbeat",
  "timestamp": 1640995200000
}

{
  // 业务通知
  "type": "notification",
  "data": {
    "title": "新消息",
    "content": "您有一条新的消息",
    "priority": "normal"
  }
}

{
  // 数据更新
  "type": "data_update",
  "data": {
    "entity": "user_profile",
    "action": "update",
    "payload": { /* 更新的数据 */ }
  }
}

故障排除

1. 常见问题

问题:连接建立失败

错误信息: "Failed to connect to SSE server"

解决方案:

  1. 检查服务器地址是否正确
  2. 验证网络连接
  3. 检查服务器是否正常运行
// 调试代码
console.log('SSE URL:', this.sseConfig.url);
console.log('请求头:', this.sseConfig.headers);

// 使用 curl 测试服务器
// curl -N -H "Accept: text/event-stream" -H "Authorization: Bearer your-token" https://your-server.com/api/sse

问题:认证失败 (401 错误)

错误信息: "Unauthorized"

解决方案:

  1. 检查 token 是否正确
  2. 验证 token 是否过期
  3. 确认请求头格式正确
// 检查 token
computed: {
  sseHeaders() {
    const token = this.$store.state.userInfo.accessToken;
    console.log('当前 token:', token); // 调试用

    if (!token) {
      console.warn('SSE: 缺少认证 token');
      return {};
    }

    return {
      'Authorization': `Bearer ${token}`
    };
  }
}

问题:频繁重连

日志: "SSE reconnecting attempt 3/5"

解决方案:

  1. 检查服务器稳定性
  2. 调整重连参数
  3. 优化网络环境
// 调整重连配置
<uni-sse
  :reconnectAttempts="3"      // 减少重连次数
  :reconnectInterval="5000"   // 增加重连间隔
/>

2. 调试工具

启用详细日志

// 在组件中添加调试开关
data() {
  return {
    debugMode: process.env.NODE_ENV === 'development'
  }
},

methods: {
  onMessage(event) {
    if (this.debugMode) {
      console.log('SSE 消息详情:', {
        id: event.id,
        type: event.type,
        data: event.data,
        timestamp: Date.now()
      });
    }
    // 处理消息...
  }
}

网络请求监控

// 在浏览器开发者工具中
// 1. 打开 Network 标签页
// 2. 筛选 "EventStream" 类型的请求
// 3. 查看请求详情和响应流

性能监控

// 监控连接性能
const connectionStart = Date.now();

onConnected() {
  const connectionTime = Date.now() - connectionStart;
  console.log(`SSE 连接耗时: ${connectionTime}ms`);
}

3. 错误码对照表

错误码 说明 解决方案
400 请求格式错误 检查请求参数和格式
401 认证失败 检查 token 有效性
403 权限不足 确认用户权限
404 端点不存在 检查 URL 路径
429 请求过频 减少连接频率
500 服务器内部错误 联系服务器管理员
502 网关错误 检查服务器代理配置
503 服务不可用 等待服务恢复

最佳实践

1. 连接管理

// ✅ 好的做法:统一连接管理
export default {
  data() {
    return {
      sseConnected: false
    }
  },

  created() {
    // 监听用户登录状态
    this.$store.watch(
      (state) => state.userInfo.accessToken,
      (newToken, oldToken) => {
        if (newToken && !oldToken) {
          // 用户登录,建立 SSE 连接
          this.connectSSE();
        } else if (!newToken && oldToken) {
          // 用户登出,断开 SSE 连接
          this.disconnectSSE();
        }
      }
    );
  },

  methods: {
    connectSSE() {
      if (this.$refs.sse && !this.sseConnected) {
        this.$refs.sse.connect();
      }
    },

    disconnectSSE() {
      if (this.$refs.sse && this.sseConnected) {
        this.$refs.sse.disconnect();
      }
    }
  }
}

2. 消息处理

// ✅ 好的做法:结构化消息处理
methods: {
  handleMessage(event) {
    const { data } = event;

    // 验证消息格式
    if (!data || typeof data !== 'object') {
      console.warn('SSE: 收到无效消息格式', data);
      return;
    }

    // 根据消息类型路由处理
    const handlers = {
      'notification': this.handleNotification,
      'data_update': this.handleDataUpdate,
      'system_alert': this.handleSystemAlert,
      'heartbeat': this.handleHeartbeat
    };

    const handler = handlers[data.type];
    if (handler) {
      handler(data);
    } else {
      console.warn('SSE: 未知消息类型', data.type);
    }
  },

  handleNotification(data) {
    // 显示通知
    uni.showToast({
      title: data.title,
      icon: 'none'
    });
  },

  handleDataUpdate(data) {
    // 更新本地数据
    this.$store.dispatch('updateData', data.payload);
  }
}

3. 错误处理

// ✅ 好的做法:优雅的错误处理
methods: {
  onError(error) {
    // 记录错误日志
    this.logError('SSE_ERROR', {
      message: error.message,
      timestamp: Date.now(),
      userAgent: navigator.userAgent
    });

    // 用户友好的错误提示
    const userFriendlyMessage = this.getUserFriendlyErrorMessage(error);
    this.showErrorNotification(userFriendlyMessage);

    // 根据错误类型决定是否重试
    if (this.shouldRetry(error)) {
      this.scheduleRetry();
    } else {
      this.handleFatalError(error);
    }
  },

  getUserFriendlyErrorMessage(error) {
    const errorMessages = {
      'network': '网络连接失败,请检查网络设置',
      'auth': '认证失败,请重新登录',
      'server': '服务器暂时不可用,请稍后重试',
      'default': '连接出现问题,正在尝试重新连接'
    };

    const errorType = this.classifyError(error);
    return errorMessages[errorType] || errorMessages.default;
  }
}

4. 性能优化

// ✅ 好的做法:性能优化
export default {
  data() {
    return {
      messageBuffer: [], // 消息缓冲区
      processingMessages: false
    }
  },

  methods: {
    onMessage(event) {
      // 将消息添加到缓冲区
      this.messageBuffer.push(event);

      // 批量处理消息,避免阻塞 UI
      if (!this.processingMessages) {
        this.processingMessages = true;
        this.$nextTick(() => {
          this.processMessageBuffer();
          this.processingMessages = false;
        });
      }
    },

    processMessageBuffer() {
      const messages = this.messageBuffer.splice(0);
      messages.forEach(message => {
        this.handleSingleMessage(message);
      });
    },

    handleSingleMessage(message) {
      // 处理单条消息
      try {
        this.processBusinessLogic(message);
      } catch (error) {
        console.error('处理消息时出错:', error);
      }
    }
  },

  beforeDestroy() {
    // 确保清理资源
    this.messageBuffer = [];
    if (this.$refs.sse) {
      this.$refs.sse.disconnect();
    }
  }
}

5. 测试建议

// ✅ 测试用例示例
describe('SSE 功能测试', () => {
  let wrapper;

  beforeEach(() => {
    wrapper = mount(SSEComponent, {
      propsData: {
        url: 'ws://localhost:3000/sse',
        autoConnect: false
      }
    });
  });

  test('应该能够成功建立连接', async () => {
    wrapper.vm.connect();
    await wrapper.vm.$nextTick();

    expect(wrapper.vm.isConnected).toBe(true);
  });

  test('应该能够接收和处理消息', async () => {
    const mockMessage = {
      id: '123',
      data: { type: 'test', content: 'hello' },
      type: 'message'
    };

    wrapper.vm.onMessage(mockMessage);

    expect(wrapper.vm.messages).toContain(mockMessage);
  });

  test('应该能够优雅地处理连接错误', async () => {
    const mockError = { message: 'Connection failed' };

    wrapper.vm.onError(mockError);

    expect(wrapper.vm.error).toEqual(mockError);
  });
});

技术支持

如果在使用过程中遇到问题,请:

  1. 查看浏览器开发者工具的 Console 和 Network 标签页
  2. 检查服务器端的日志
  3. 参考本文档的故障排除部分
  4. 使用测试页面 /pages/sse-test/sse-test 进行调试

更多技术细节请参考:


版本信息:

  • 文档版本: 1.0.0
  • 最后更新: 2024年12月
  • 适用平台: H5, Android, iOS

隐私、权限声明

1. 本插件需要申请的系统权限列表:

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:

许可协议

MIT协议

暂无用户评论。