sse
- 实现效果
- 代码
- 前端
- 后端
实现效果
服务端返回的 Content-Type 是 text/event-stream,这是一个流,可以多次返回内容。
Sever Sent Event 就是通过这种消息来随时推送数据。
AIGC,如 ChatGPT 打字机消息回复实现原理 等也是使用sse实现。
还有站内信,或者一些日志推送,相较于繁重的 WebSockets,SSE 无疑是 H5 简单即时数据更新的轻量级代替方案。
源码:https://github.com/thinkasany/nestjs-course-code/tree/master/sse
代码
前端
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>React App</title>
</head>
<body><div id="root"></div><script crossorigin src="https://unpkg.com/@babel/standalone/babel.min.js"></script><script crossorigin src="https://unpkg.com/react@17/umd/react.production.min.js"></script><script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.production.min.js"></script><script type="text/babel">function App() {const [messages, setMessages] = React.useState([]);React.useEffect(() => {const eventSource = new EventSource('http://localhost:3001/stream');eventSource.onmessage = ({ data }) => {const newData = JSON.parse(data).msg.split('\n').filter(str => str.trim() !== '');// console.log('New message', newData);setMessages(newData);};return () => {eventSource.close();};}, []);return (<div><ul>{messages.map((message, index) => (<li key={index}>{message}</li>))}</ul></div>);};ReactDOM.render(<App />, document.getElementById('root'));</script>
</body>
</html>
后端
const { exec } = require("child_process");
const { Observable } = require("rxjs");const getLogChange = async (req, res) => {const childProcess = exec("tail -f ./log");res.setHeader("Content-Type", "text/event-stream");res.setHeader("Cache-Control", "no-cache");res.setHeader("Connection", "keep-alive");const observer = msg => {res.write(`data: ${JSON.stringify({ msg: msg.toString() })}\n\n`);};const observable = new Observable(obs => {childProcess.stdout.on("data", msg => {obs.next(msg);});});const subscription = observable.subscribe(observer);// 当连接断开时,停止子进程和 Observablereq.on("close", () => {childProcess.kill();subscription.unsubscribe();});
};module.exports = {getLogChange
};