结论
-
对于响应头的
Content-Type字段包含text/event-stream的接口会分段的向客户端进行响应(res.write响应数据,res.end结束接口响应) -
客户端处理流式接口有两种方式:
- 通过sse(Server-Sent Events)接口
EventSource来实现对流式接口的监听(onmessage回调感知每一次res.write& 客户端与服务端接口断开连接后会自动重连)。 - 使用
fetch发送网络请求,fetchRes.body为ReadableStream(axios无法处理流式接口,xhr没有提供处理能力)
- 通过sse(Server-Sent Events)接口
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>