流式数据处理

2,183 阅读1分钟

星空.png

结论

  • 对于响应头的Content-Type字段包含text/event-stream的接口会分段的向客户端进行响应(res.write响应数据,res.end结束接口响应)

  • 客户端处理流式接口有两种方式:

    • 通过sse(Server-Sent Events)接口EventSource来实现对流式接口的监听(onmessage回调感知每一次res.write & 客户端与服务端接口断开连接后会自动重连)。
    • 使用fetch发送网络请求,fetchRes.bodyReadableStream(axios无法处理流式接口,xhr没有提供处理能力)

demo

服务端代码:

const express = require('express');
const cors = require('cors');
const app = express();
​
app.use(cors());
​
app.get('/events', function(req, res) {
  res.setHeader('Content-Type', 'text/event-stream; charset=utf-8');
  res.setHeader('Cache-Control', 'no-cache');
  res.setHeader('Connection', 'keep-alive');
​
  let respondTime = 3;
​
  const sendEvent = (data) => {
    return res.write(`data: ${JSON.stringify(data)}\n\n`);
  };
​
  const endEvent = () => {
    res.end();
  };
  
  const timer = setInterval(() => {
    if(respondTime) {
        const message = { time: new Date().toISOString(), message: `Hello World has send ${4 - respondTime} times` };
        sendEvent(message);
    } else {
        endEvent();
        clearInterval(timer);
    }
    respondTime--;
  }, 1000);
});
​
const port = 3001;
app.listen(port, () => {
  console.log(`server running at http://localhost:${port}`);
});

客户端代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>SSE Example</title>
</head>
<body>
    <script>
        const url = 'http://localhost:3001/events';
​
        // -------------EventSource--------------
​
        const evtSource = new EventSource(url);
        evtSource.onmessage = function(event) {
            const message = JSON.parse(event.data);
            console.log(message);
        };
​
        // -------------fetch--------------
​
        const getStream = async () => {
            const res = await fetch(url);
            const reader = res.body.getReader();
            const decoder = new TextDecoder('utf-8');
            const read = async () => {
                const {done, value} = await reader.read();
                if(!done) {
                    console.log(decoder.decode(value, { stream: true }));
                    read();
                }
            }
            read();
        }
        getStream();
    </script>
</body>
</html>