前端接收流式数据的完整方案(SSE/WebSocket/Fetch API)

2,321 阅读2分钟

前端接收流式数据的完整方案(SSE/WebSocket/Fetch API)


一、流式数据

什么是流式数据?

  • 数据分多次传输,无需等待完整内容即可开始处理
  • 典型场景:实时日志、股票行情、AI生成内容(如ChatGPT逐字输出)

二、5种主流实现方案

1. Server-Sent Events (SSE)

特点

  • 单向通信(服务端→客户端)
  • 基于HTTP协议,自动重连
  • 兼容性:除IE外主流浏览器均支持

代码示例

const eventSource = new EventSource('/api/stream');

// 接收消息
eventSource.onmessage = (event) => {
  console.log('New data:', event.data);
};

// 自定义事件类型
eventSource.addEventListener('stockUpdate', (e) => {
  const data = JSON.parse(e.data);
  updateStockChart(data);
});

// 错误处理
eventSource.onerror = () => {
  console.error('Stream failed');
};

服务端要求

Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive

2. WebSocket

特点

  • 全双工通信
  • 适合高频双向数据交换

代码示例

const socket = new WebSocket('wss://api.example.com/stream');

socket.onopen = () => {
  socket.send('subscribe:stocks'); // 发送初始指令
};

socket.onmessage = (event) => {
  const data = JSON.parse(event.data);
  renderRealTimeData(data);
};

socket.onclose = () => {
  console.log('Disconnected');
};

协议对比

维度SSEWebSocket
协议HTTPWS/WSS
方向单向双向
二进制支持仅文本支持二进制
自动重连

3. Fetch API + Streams API

特点

  • 精细控制数据流
  • 适合处理大文件下载

代码示例

const response = await fetch('/api/large-file');
const reader = response.body.getReader();

while (true) {
  const { done, value } = await reader.read();
  if (done) break;
  
  // 处理分块数据(Uint8Array)
  const text = new TextDecoder().decode(value);
  console.log('Chunk:', text);
}

应用场景

  • 逐行读取CSV文件
  • 视频流处理

4. XMLHttpRequest (旧式方案)

兼容性方案

const xhr = new XMLHttpRequest();
xhr.open('GET', '/api/stream');

xhr.onprogress = (event) => {
  const newData = xhr.responseText.substr(lastIndex);
  processData(newData);
};

xhr.send();

5. Web Workers + Stream(CPU密集型处理)

优化方案

// 主线程
const worker = new Worker('stream-worker.js');
worker.postMessage({ cmd: 'start', url: '/api/stream' });

// worker.js
self.onmessage = async (e) => {
  const response = await fetch(e.data.url);
  const reader = response.body.getReader();
  
  while (true) {
    const { done, value } = await reader.read();
    self.postMessage({ data: value });
    if (done) break;
  }
};

三、关键问题解决方案

  1. 数据完整性

    • 使用分隔符(如\n\n
    • 实现ACK确认机制(WebSocket)
  2. 性能优化

    // 防抖处理高频数据
    let buffer = [];
    const debounceRender = _.debounce(() => {
      render(buffer);
      buffer = [];
    }, 100);
    
    socket.onmessage = (event) => {
      buffer.push(event.data);
      debounceRender();
    };
    
  3. 错误恢复

    // SSE自动重连
    eventSource.onerror = () => {
      setTimeout(() => new EventSource(url), 5000);
    };
    

四、现代框架集成

React示例(SSE + Hook)
function useStream(url) {
  const [data, setData] = useState('');

  useEffect(() => {
    const es = new EventSource(url);
    es.onmessage = (e) => {
      setData(prev => prev + e.data);
    };
    return () => es.close();
  }, [url]);

  return data;
}

// 使用
const logs = useStream('/api/log-stream');
Vue示例(WebSocket)
export default {
  data() {
    return {
      stockData: []
    }
  },
  created() {
    this.socket = new WebSocket('wss://stocks.com');
    this.socket.onmessage = (e) => {
      this.stockData.push(JSON.parse(e.data));
    };
  },
  beforeUnmount() {
    this.socket.close();
  }
}

五、调试工具

  1. Chrome DevTools

    • Network面板查看SSE/WS连接
    • 流数据实时监控
  2. 测试工具

    # 模拟SSE服务
    printf "data: test1\n\n" | nc -l 8080
    

六、服务端配合要求

技术响应头数据格式
SSEtext/event-streamdata: {...}\n\n
WebSocketUpgrade: websocket二进制/文本
FetchTransfer-Encoding: chunked分块编码

上面这些方案可以实现: ✅ 实时聊天应用
✅ 金融行情看板
✅ 大文件逐块处理
✅ AI生成内容流式展示