柚子快報(bào)邀請(qǐng)碼778899分享:[字節(jié)青訓(xùn)
1.SSE基礎(chǔ)
以下是關(guān)于 Server-Sent Events (SSE) 的前后端交互規(guī)范、常見方法及自定義擴(kuò)展的完整指南:
一、SSE 交互規(guī)范
1. 基礎(chǔ)協(xié)議
HTTP 協(xié)議:基于 HTTP/1.1 長(zhǎng)連接,響應(yīng)頭需包含:
Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive
2. 數(shù)據(jù)格式規(guī)范
每條消息格式為:
[field]: value\n
支持字段:
data:消息內(nèi)容(必填)
event:自定義事件類型(默認(rèn) message)
id:消息ID(用于斷線重連定位)
retry:重連時(shí)間(毫秒)
示例:標(biāo)準(zhǔn)數(shù)據(jù)流
event: status
{"progress": 75%}
This is a message\n
with two lines
id: 12345
retry: 5000
二、常見方法
1. 前端基礎(chǔ)用法
const es = new EventSource('/api/stream');
// 監(jiān)聽默認(rèn)事件
es.onmessage = ({
data }) => console.log('Received:', data);
// 監(jiān)聽自定義事件
es.addEventListener('update', ({
data }) => {
console.log('Update:', JSON.parse(data));
});
// 錯(cuò)誤處理
es.onerror = () => console.error('Connection lost');
2. 后端基礎(chǔ)實(shí)現(xiàn)(Node.js)
app.get('/api/stream', (req, res) => {
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Access-Control-Allow-Origin': '*' // 處理跨域
});
// 發(fā)送初始數(shù)據(jù)
res.write('Connected\n\n');
// 定時(shí)推送數(shù)據(jù)
const timer = setInterval(() => {
res.write(`${
Date.now()}\n\n`);
}, 1000);
// 客戶端斷開時(shí)清理
req.on('close', () => clearInterval(timer));
});
三、自定義擴(kuò)展方法
1. 身份驗(yàn)證
前端:通過 URL 參數(shù)或 Cookie 傳遞 Token
new EventSource('/api/stream?token=xxxx')
后端:驗(yàn)證 Token 有效性
app.get('/api/stream', (req, res) => {
if (!validateToken(req.query.token)) {
res.writeHead(401).end();
return;
}
// ...后續(xù)推送邏輯
});
2. 結(jié)構(gòu)化數(shù)據(jù)傳遞
使用 JSON 編碼:
// 前端解析
es.onmessage = ({
data }) => {
const msg = JSON.parse(data);
console.log(msg.type, msg.content);
};
// 后端發(fā)送
res.write(`data:${
JSON.stringify({
type: 'alert', content: 'Warning' })}\n\n`);
3. 分塊傳輸大文本(流式數(shù)據(jù)處理)
// 后端分塊發(fā)送
const bigText = "Very long text...";
for (const chunk of chunkText(bigText, 100)) {
// 每100字符分塊
res.write(`event: chunk\n${
chunk}\n\n`);
}
// 前端組裝
let fullText = '';
es.addEventListener('chunk', ({
data }) => {
fullText += data;
});
4. 雙向通信模擬
SSE 是單向通道,但可通過以下方式模擬雙向:
// 前端通過 AJAX 發(fā)送控制命令
function sendCommand(cmd) {
fetch('/api/control', {
method: 'POST', body: cmd });
}
// 后端響應(yīng)命令并推送結(jié)果
app.post('/api/control', (req, res) => {
handleCommand(req.body, (result) => {
sseClients.forEach(client =>
client.res.write(`event: command-result\n${
result}\n\n`)
);
});
res.status(200).end();
});
四、高級(jí)實(shí)踐
1. 性能優(yōu)化
壓縮數(shù)據(jù):?jiǎn)⒂?gzip 壓縮
app.use(compression()); // Express 中間件
心跳檢測(cè):防止代理超時(shí)(核心,面試?。。。?/p>
setInterval(() => res.write(': ping\n\n'), 30000);
3. 錯(cuò)誤恢復(fù)
(重連,簡(jiǎn)歷)
let es = null;
function connectSSE() {
es = new EventSource('/api/stream');
es.onerror = () => {
es.close();
setTimeout(connectSSE, 5000); // 5秒后重連
};
}
connectSSE(); // 初始連接
五、注意事項(xiàng)
跨域問題 確保響應(yīng)頭包含 Access-Control-Allow-Origin,或通過代理解決。
連接限制 瀏覽器對(duì)單個(gè)域名 SSE 連接數(shù)有限制(通常 6 個(gè)),需合理設(shè)計(jì)連接復(fù)用。
數(shù)據(jù)安全 敏感數(shù)據(jù)需加密或通過 HTTPS 傳輸。
兼容性 SSE 不支持 IE,需使用 Polyfill(如 eventsource 庫(kù))。
通過上述規(guī)范和擴(kuò)展方法,SSE 可靈活應(yīng)用于實(shí)時(shí)監(jiān)控、消息推送、日志流等場(chǎng)景。開發(fā)者應(yīng)根據(jù)具體需求選擇合適的數(shù)據(jù)格式和通信模式。
2.前端SSE類封裝
//EventSourceWrapper.js
type EventSourceConfig = {
url: string;
queryParams?: Record
onMessage: (string) => void; // 直接傳遞數(shù)據(jù)
onError?: (error: Error) => void;
};
export class EventSourceWrapper {
private eventSource: EventSource | null = null;
constructor(private
柚子快報(bào)邀請(qǐng)碼778899分享:[字節(jié)青訓(xùn)
本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點(diǎn)和立場(chǎng)。
轉(zhuǎn)載請(qǐng)注明,如有侵權(quán),聯(lián)系刪除。