created at 2023/08/03 04:09:11
updated at 2023/08/03 05:11:23
SSE 是指服务器主动向客户端发送消息或通知。这种通信方式常用于实时应用程序或实时更新的场景,例如聊天应用、实时数据更新等。
SSE 可以通过不同的方式实现,其中一种常见的方式是使用服务器推送技术,如 WebSocket 或长轮询。通过这些技术,服务器可以保持与客户端的持久连接,并在有新事件时立即将消息推送给客户端。
SSE 的基本流程如下:
客户端与服务器建立连接,例如通过 WebSocket 或 HTTP 长轮询等方式。 服务器监视事件的发生,如新消息到达、数据更新等。 当有事件发生时,服务器将事件消息发送给客户端。 客户端接收到事件消息后,可以根据需要进行相应的处理,如更新界面、显示通知等。 通过 SSE,可以实现实时的双向通信,使得服务器可以主动向客户端发送消息,而不需要客户端主动发起请求。这种方式可以提高应用程序的实时性和交互性,使得用户能够及时地接收到最新的信息。
javascript
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
const port = process.env.PORT || 5000;
app.use((req, res, next) => {
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:3000');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type,Authorization');
next();
});
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
let Data = null; // 存储处理后的数据
function processData(data) {
// 处理数据的逻辑
return data;
}
app.post('/data', (req, res) => {
console.log('the client send request !!! connected...');
res.setHeader('Access-Control-Allow-Origin', '*');
const apiKey = req.headers.authorization.split(' ')[1];
const reqdata = req.body;
console.log('apiKey', apiKey);
console.log('data:', reqdata);
if (apiKey !== '123456789') {
res.status(401).send('Unauthorized');
return;
}
// 对数据进行处理
Data = processData(reqdata);
res.status.send('ok');
});
app.get('/sse', (req, res) => {
res.setHeader('Content-Type', 'text/event-stream');
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Connection', 'keep-alive');
const intervalId = setInterval(() => {
if (Data) {
const date = new Date().toLocaleString();
const resdata = {
date,
content: Data,
};
res.write(`data: ${JSON.stringify(resdata)}\n\n`);
}
}, 1000);
res.on('close', () => {
clearInterval(intervalId);
res.end();
});
});
app.listen(port, () => {
console.log(`app is running on localhost:${port}`);
});
发送 post 请求,服务端处理数据
处理数据通过另一个接口返回
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>sse</title>
</head>
<body>
<div id="control">
<button id="send">send</button>
<button id="closed">close</button>
</div>
<div id="messages"></div>
<script>
const updateMessage = (msg) => {
const msgs = document.getElementById('messages');
const msgElement = document.createElement('p');
msgElement.textContent = msg;
msgs.appendChild(msgElement);
};
const send = document.getElementById('send');
const closeBtn = document.getElementById('closed');
const closeConn = (callback) => {
closeBtn.addEventListener('click', callback);
};
send.addEventListener('click', () => {
const data = { time: 'now', conent: 'hello!!!' };
fetch('http://localhost:5000/data', {
method: 'POST',
headers: {
Authorization: 'Bearer 123456789',
'Content-Type': 'application/json',
Origin: '*',
},
body: JSON.stringify(data),
}).then((response) => {
if (!response.ok) {
throw new Error('Network response was not ok');
}
const eventSource = new EventSource('http://localhost:5000/sse');
eventSource.onopen = () => {
updateMessage('server is connected...');
};
eventSource.onmessage = (e) => {
updateMessage(e.data);
};
eventSource.onerror = (e) => {
updateMessage('server is closed...');
eventSource.close();
};
closeConn(() => {
eventSource.close();
});
});
});
</script>
</body>
</html>
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>sse</title>
</head>
<body>
<div id="control">
<button id="send">send</button>
<button id="closed">close</button>
</div>
<div id="messages"></div>
<script>
const updateMessage = (msg) => {
const msgs = document.getElementById('messages');
const msgElement = document.createElement('p');
msgElement.textContent = msg;
msgs.appendChild(msgElement);
};
const send = document.getElementById('send');
const closeBtn = document.getElementById('closed');
const closeConn = (callback) => {
closeBtn.addEventListener('click', callback);
};
function processStream(stream, processChunk) {
const reader = stream.getReader();
function read() {
reader.read().then(({ done, value }) => {
if (done) {
return;
}
const decoder = new TextDecoder('utf-8');
const text = decoder.decode(value);
processChunk(text);
read();
});
}
read();
return reader;
}
send.addEventListener('click', () => {
const data = { time: 'now', conent: 'hello!!!' };
fetch('http://localhost:5000/data', {
method: 'POST',
headers: {
Authorization: 'Bearer 123456789',
'Content-Type': 'application/json',
Origin: '*',
},
body: JSON.stringify(data),
})
.then((response) => response.body)
.then((body) => {
const reader = processStream(body, (text) => {
console.log(text);
});
closeConn(() => {
reader.cancel(); // 只取消了读取流,如果服务端没有控制,还有数据流接受
});
});
});
</script>
</body>
</html>
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>sse</title>
</head>
<body>
<div id="control">
<button id="send">send</button>
<button id="closed">close</button>
</div>
<div id="messages"></div>
<script>
const updateMessage = (msg) => {
const msgs = document.getElementById('messages');
const msgElement = document.createElement('p');
msgElement.textContent = msg;
msgs.appendChild(msgElement);
};
const send = document.getElementById('send');
const closeBtn = document.getElementById('closed');
const closeConn = (callback) => {
closeBtn.addEventListener('click', callback);
};
function processStream(stream, processChunk) {
const reader = stream.getReader();
function read() {
reader.read().then(({ done, value }) => {
if (done) {
return;
}
const decoder = new TextDecoder('utf-8');
const text = decoder.decode(value);
processChunk(text);
read();
});
}
read();
return reader;
}
send.addEventListener('click', () => {
const data = { time: 'now', conent: 'hello!!!' };
const controller = new AbortController();
const signal = controller.signal;
fetch('http://localhost:5000/data', {
method: 'POST',
headers: {
Authorization: 'Bearer 123456789',
'Content-Type': 'application/json',
Origin: '*',
},
body: JSON.stringify(data),
signal,
})
.then((response) => response.body)
.then((body) => {
const reader = processStream(body, (text) => {
console.log(text);
});
closeConn(() => {
reader.cancel();
controller.abort();
});
});
});
</script>
</body>
</html>