🌟 效果预览
- 实时流式消息推送
- Markdown代码高亮渲染
- 智能错误处理与Token失效检测
- 自适应文本输入框
- 响应式消息气泡布局
📦 第三方库清单
npm install --save \
event-source-polyfill \
element-plus \
marked marked-highlight \
highlight.js \
dompurify \
dayjs
🛠️ 核心实现解析
1. SSE连接管理
// 智能重连机制
const createSSEConnection = (url, options) => {
const eventSource = new EventSourcePolyfill(API_URL + url, {
headers: { Authorization: localStorage.getItem('token') },
heartbeatTimeout: 60 * 1000, // 心跳检测
withCredentials: true
});
// 三路事件监听
eventSource.addEventListener('open', () => {
console.log('SSE通道建立成功');
options?.onOpen?.();
});
eventSource.addEventListener('message', (event) => {
try {
const data = JSON.parse(event.data);
// 分片数据聚合
if(data.chunk) {
bufferManager.addChunk(data.chunk);
}
options?.onMessage?.(data);
} catch(error) {
errorHandler('数据解析异常', error);
}
});
// 智能错误处理
eventSource.addEventListener('error', (error) => {
if(error.status === 401) {
showReLoginModal(); // 会话过期提示
} else if(error.status >= 500) {
scheduleReconnect(); // 服务端错误自动重连
}
});
return { eventSource, close: () => eventSource.close() };
};
2. 消息处理机制
流式数据特征:
- 分片到达顺序保证
- 实时渲染性能优化
- 大文本内存管理
// 消息队列处理
const processChunk = (chunk) => {
messages.value[activeIndex].content += chunk;
// 渲染节流优化
if(!renderScheduled) {
renderScheduled = true;
requestAnimationFrame(() => {
updateScrollPosition();
renderScheduled = false;
});
}
};
3. Markdown安全渲染
// 防御性渲染策略
const safeRenderer = (rawContent) => {
const cleanHTML = DOMPurify.sanitize(
marked.parse(rawContent),
{
ALLOWED_TAGS: ['code', 'pre', 'table', ...MARKDOWN_TAGS],
FORBID_ATTR: ['style', 'onerror']
}
);
// 动态语法高亮
nextTick(() => {
document.querySelectorAll('pre code').forEach(block => {
hljs.highlightElement(block);
});
});
return cleanHTML;
};
💡 性能优化技巧
- 滚动节流技术
let isScrolling = false;
const smoothScroll = () => {
if (!isScrolling) {
isScrolling = true;
messagesContainer.value.scrollTo({
top: messagesContainer.value.scrollHeight,
behavior: 'smooth'
});
requestAnimationFrame(() => isScrolling = false);
}
};
- 内存管理策略
interface MessageCache {
maxLength: number;
pruningRatio: number;
messagePool: Array<Message>;
pruneMessages(): void {
if(this.messagePool.length > this.maxLength) {
this.messagePool.splice(0, Math.floor(this.maxLength * this.pruningRatio));
}
}
}
🚀 部署注意事项
- Nginx配置SSE支持:
proxy_buffering off;
proxy_cache off;
proxy_read_timeout 24h;
- 安全防护措施:
- 启用CORS白名单
- 添加速率限制
- 实施请求签名验证