forked from erp-dev/erp
feat: big version, added tasks for backup_database and stock change, added health check api, approve sse (support channel via merchant)
This commit is contained in:
187
sse/client_example.js
Normal file
187
sse/client_example.js
Normal file
@@ -0,0 +1,187 @@
|
||||
/**
|
||||
* 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) => { /* 处理错误 */ },
|
||||
// () => { /* 处理关闭 */ }
|
||||
// );
|
||||
Reference in New Issue
Block a user