axios post请求 接收sse[eventsource]数据的_axios sse
axios 接收sse数据的
axios 接收sse数据的
EventSource什么
基于 HTTP 协议实现,通过与服务器建立一个持续连接,实现了服务器向客户端推送事件数据的功能。在客户端,EventSource 对象通过一个 URL 发起与服务器的连接。连接成功后,服务器可以向客户端发送事件数据。在客户端,通过 EventSource 对象注册事件处理函数,以接收来自服务器的事件数据。
EventSource的工作原理
1. 客户端发起一个 HTTP 请求,请求 URL 为服务器提供的 URL。2. 服务器收到请求后,会建立一个持续连接,客户端和服务器之间保持着一个持久的连接。3. 服务器向客户端发送事件数据,事件数据以文本形式发送,格式为 \"event: data\"。4. 客户端通过 EventSource 对象注册事件处理函数,以接收来自服务器的事件数据。5. 客户端可以通过 EventSource 对象的 close() 方法关闭连接。
项目的需求
最近在做一个项目,里面有个机器人,里面有个知识库回答功能,根据用户发送的数据,,需要从服务器接收数据,并且实时更新。整个项目去哪不使用的封装的axios库,而且全部使用的post请求,但是 axios 库没有提供接收 sse 数据的方法。EventSource 库可以实现接收 sse 数据的功能。但是不支持post请求。在加上axios 封装好多东西,所以只能只用封装的axios库。经过查多方资料,测试,终于实现了接收 sse 数据的功能。为了测试特意写了node后端的和前端的代码。
node 后端实现sse数据的发送
1. 安装 express 和 cors 库2. 编写路由文件,使用 res.write() 方法发送数据3. 启动服务器,监听端口
const express = require(\'express\');const cors = require(\'cors\');const app = express();const port = 3000;// 设置CORS策略,允许所有来源的请求app.use(cors());let counter = 0;// SSE 路由app.get(\'/events\', (req, res) => { // 设置响应头,告诉浏览器这是一个 SSE 流 res.setHeader(\'Content-Type\', \'text/event-stream\'); res.setHeader(\'Cache-Control\', \'no-cache\'); res.setHeader(\'Connection\', \'keep-alive\'); // 每秒推送一次数据 const intervalId = setInterval(() => { counter++; res.write(`data: ${JSON.stringify({ counter })}\\n\\n`); // 模拟关闭连接 if (counter === 10) { clearInterval(intervalId); res.write(\'data: {\"message\": \"Stream ended\"}\\n\\n\'); res.end(); } }, 1000); // 当客户端断开连接时,清理定时器 req.on(\'close\', () => { clearInterval(intervalId); });});app.post(\'/events2\', (req, res) => { // 设置响应头,告诉浏览器这是一个 SSE 流 res.setHeader(\'Content-Type\', \'text/event-stream\'); res.setHeader(\'Cache-Control\', \'no-cache\'); res.setHeader(\'Connection\', \'keep-alive\'); let tottal = 0; // 每秒推送一次数据 const intervalId = setInterval(() => { tottal++; res.write(`data: ${JSON.stringify({ message: tottal })}\\n\\n`); // 模拟关闭连接 if (tottal === 10) { clearInterval(intervalId); res.write(\'data: {\"message\": \"Stream ended\"}\\n\\n\'); res.end(); } }, 1000); // 当客户端断开连接时,清理定时器 req.on(\'close\', () => { clearInterval(intervalId); });});app.listen(port, () => { console.log(`Server is running on http://localhost:${port}`);});
上面的实现一个get和一个post请求,都是sse数据的发送。
前端实现sse数据的接收
前端很简单,直接使用html axios 直接使用cdn,或者下载本地直接引入,我直接现在本地直接使用的
<!DOCTYPE html><html lang=\"en\"><head> <meta charset=\"UTF-8\"> <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"> <title>Document</title>```html<!DOCTYPE html><html lang=\"en\"><head> <meta charset=\"UTF-8\"> <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"> <title>Axios POST Request Example</title> <script src=\"./axios.js\"></script> </head><body> <h1>Axios POST Request Example</h1> <div> <label for=\"name\">Name:</label> <input type=\"text\" id=\"name\" placeholder=\"Enter your name\"> </div> <div> <label for=\"message\">Message:</label> <input type=\"text\" id=\"message\" placeholder=\"Enter a message\"> </div> <button id=\"sendRequest\">Send POST Request</button> <div id=\"response\"></div> <script> // 获取按钮和输入框元素 const sendRequestButton = document.getElementById(\'sendRequest\'); const nameInput = document.getElementById(\'name\'); const messageInput = document.getElementById(\'message\'); const responseDiv = document.getElementById(\'response\'); let buffer = \'\'; // 绑定按钮点击事件 sendRequestButton.addEventListener(\'click\', function () { // 获取输入框的值 const name = nameInput.value; const message = messageInput.value; // 创建要发送的数据 const data = { name: name, message: message };// function startPolling() {// let xhr = new XMLHttpRequest(); // // 创建一个定时的 HTTP 请求,每隔一定时间向服务器发送请求// function poll() {// xhr.open(\'GET\', \'http://localhost:3000/events\', true);// xhr.onreadystatechange = function() {// const data = xhr.responseText;// console.log(\'Received data:\', data);// // if (xhr.readyState === 4 && xhr.status === 200) {// // // 服务器返回数据// // const data = xhr.responseText;// // console.log(\'Received data:\', data);// // }// };// // 发送请求// xhr.send();// // 继续每 2 秒轮询一次// }// // 启动轮询// poll();// }// startPolling(); axios.post(\'http://localhost:3000/events2\', {}, { onDownloadProgress: progressEvent => { console.log(\'progressEvent\', progressEvent) let {responseText} = progressEvent.event.target const newData = responseText.slice(buffer.length) buffer += newData // const events = buffer.split(\'\\n\\n\') const events = buffer.split(\'\\n\\n\').map(item => { const data = item.replace(/^data: /, \'\').trim() // return data try { return JSON.parse(data) } catch (error) { return \'\' } }) debugger buffer = events.pop() // 剩余部分保留到下一次 // events.forEach(event => { // if (event.trim()) { // const data = event.replace(/^data: /, \'\').trim(); // const infoData = JSON.parse(data); // console.log(\'Received event:\', infoData.message); // } // }); console.log(\'Received data:\', events, \'aaa\',buffer) }); </script></body></html>