/** * SSE客户端示例 * * 由于浏览器原生的EventSource不支持自定义请求头, * 这里提供了两种实现方式: * 1. 使用fetch实现(推荐) * 2. 使用EventSource polyfill(备选) */ /** * 方式1:使用fetch实现SSE客户端(推荐) * * @param {string} url - SSE端点URL * @param {string} token - JWT认证token * @param {function} onMessage - 接收到消息时的回调函数 * @param {function} onError - 连接错误时的回调函数 * @param {function} onClose - 连接关闭时的回调函数 */ function createSSEConnectionWithFetch(url, token, onMessage, onError, onClose) { const controller = new AbortController(); const signal = controller.signal; // 启动一个长时间运行的fetch请求 fetch(url, { method: 'GET', headers: { 'Authorization': `Bearer ${token}`, 'Accept': 'text/event-stream', 'Cache-Control': 'no-cache', }, signal: 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 = ''; function processBuffer() { const lines = buffer.split('\n'); buffer = lines.pop(); // 保留最后一个不完整的行 for (const line of lines) { if (line.trim() === '') continue; // 空行表示事件结束 if (line.startsWith('data: ')) { const data = line.substring(6); // 去掉 'data: ' 前缀 try { const event = JSON.parse(data); if (onMessage) onMessage(event); } catch (e) { console.error('Error parsing SSE data:', e); } } } } function read() { return reader.read().then(({ done, value }) => { if (done) { if (onClose) onClose(); return; } buffer += decoder.decode(value, { stream: true }); processBuffer(); // 继续读取 return read(); }); } return read(); }) .catch(error => { if (onError) onError(error); }); // 返回一个对象,包含关闭连接的方法 return { close: () => controller.abort() }; } /** * 方式2:使用EventSource Polyfill实现 * * 需要先安装EventSource polyfill: * npm install event-source-polyfill * * 在应用入口处导入: * import 'event-source-polyfill'; */ function createSSEConnectionWithPolyfill(url, token, onMessage, onError, onClose) { // 创建带有认证的URL const urlWithAuth = `${url}?token=${encodeURIComponent(token)}`; const eventSource = new EventSource(urlWithAuth); eventSource.onmessage = function(event) { try { const data = JSON.parse(event.data); if (onMessage) onMessage(data); } catch (e) { console.error('Error parsing SSE data:', e); } }; eventSource.onerror = function(error) { if (onError) onError(error); }; eventSource.onclose = function() { if (onClose) onClose(); }; return { close: () => eventSource.close() }; } /** * 使用示例 */ const JWT_TOKEN = 'your_jwt_token_here'; const SSE_URL = '/sse/'; // 使用fetch方式(推荐) const sseConnection = createSSEConnectionWithFetch( SSE_URL, JWT_TOKEN, (event) => { console.log('收到SSE事件:', event); // 根据事件类型处理不同业务逻辑 switch (event.type) { case 'connected': console.log(`SSE连接成功,商户ID: ${event.merchant_id}`); break; case 'order_paid': console.log(`订单已支付: ${event.object_id}`); // 刷新订单列表或显示通知 break; case 'stock_change_record': console.log(`库存变动记录: ${event.object_id}`); // 刷新库存数据 break; case 'server_shutdown': console.log('服务器即将关闭连接'); // 可以提示用户重新连接 break; } }, (error) => { console.error('SSE连接错误:', error); // 可以在这里实现重连逻辑 setTimeout(() => { console.log('尝试重新连接...'); // 重新创建连接 }, 5000); }, () => { console.log('SSE连接已关闭'); } ); // 当需要关闭连接时(例如用户退出登录) // sseConnection.close(); /** * 如果需要使用polyfill方式,确保在应用入口处导入polyfill */ // import 'event-source-polyfill'; // // const sseConnection = createSSEConnectionWithPolyfill( // SSE_URL, // JWT_TOKEN, // (event) => { /* 处理事件 */ }, // (error) => { /* 处理错误 */ }, // () => { /* 处理关闭 */ } // );