Node.js SSE in Action All In One
Node.js SSE in Action All In One
Node.js &
Server-sent events
SSE
Server-sent events: method of
continuously
sending data from a server to the browser, rather than repeatedly requesting it (EventSource
interface, used to fall underHTML5
)
https://caniuse.com/eventsource
var source = new EventSource('updates.cgi');
source.onmessage = function (event) {
alert(event.data);
};
var source = new EventSource('updates.cgi');
source.addEventListener('add', addHandler, false);
source.addEventListener('remove', removeHandler, false);
https://html.spec.whatwg.org/multipage/server-sent-events.html#server-sent-events
https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events
EventSource
⚠️ Warning: When not used over
HTTP/2
, SSE suffers from a limitation to the maximum number of open connections, which can be specially painful when opening various tabs as the limit is per browser and set to a very low number (6
).
The issue has been marked as "Won't fix" in Chrome and Firefox.
This limit is per browser + domain, so that means that you can open6
SSE connections across all of thetabs
to www.example1.com and another6
SSE connections to www.example2.com.
When usingHTTP/2
, the maximum number of simultaneous HTTP streams isnegotiated
between the server and the client (defaults to100
).
const evtSource = new EventSource("sse.php");
const eventList = document.querySelector("ul");
evtSource.onmessage = (e) => {
const newElement = document.createElement("li");
newElement.textContent = `message: ${e.data}`;
eventList.appendChild(newElement);
};
https://developer.mozilla.org/en-US/docs/Web/API/EventSource
demos
server.js
// const express = require('express')
// const fs = require('fs')
import fs from 'node:fs';
import express from 'express';
const app = express();
app.use(express.static('public'));
// const convertImageToBase64URL = (filename, imageType = 'png') => {
// try {
// const base64String = fs.readFileSync(filename, {
// encoding: 'base64',
// });
// console.log(`base64String`, base64String.slice(0, 100));
// return `data:image/${imageType};base64,${base64String}`;
// } catch (error) {
// throw new Error(`file ${filename} no exist ❌`)
// }
// }
const convertImageToBase64URL = (filename, imageType = 'png') => {
try {
const buffer = fs.readFileSync(filename);
const base64String = Buffer.from(buffer).toString('base64');
// console.log(`base64String`, base64String.slice(0, 100));
return `data:image/${imageType};base64,${base64String}`;
} catch (error) {
throw new Error(`file ${filename} no exist ❌`)
}
}
app.get('/img', (req, res) => {
// res.writeHead(200, {
// // 'Content-Type': 'image/jpg;base64',
// // 'Content-Type': 'image/png;base64',
// 'Content-Type': 'application/json',
// 'Cache-Control': 'no-cache',
// 'Connection': 'keep-alive',
// });
const data = convertImageToBase64URL("./public/test.png");
// console.log(`base64String`, data.slice(0, 100));
res.json({
data,
});
// res.write(data);
});
// http://localhost:3000/img
// app.get('/', (req, res) => {
// res.file(`/public/index.html`);
// });
// http://localhost:3000/
const port = 3000;
app.listen(port, () => {
console.log(`SSE server is running on: http://localhost:${port}/`);
});
<!DOCTYPE html>
<html lang="zh-Hans">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<meta name="author" content="xgqfrms">
<meta name="generator" content="VS code">
<title>Node.js SSE</title>
<script src="./client.js"></script>
</head>
<body>
<header>
<h1>Node.js SSE</h1>
</header>
<main>
<img id="img" src="" />
<!-- <img id="img" src="http://localhost:3000/img" /> -->
</main>
<footer>
<p>copyright© xgqfrms 2022</p>
</footer>
<!-- <script type="module" src="./client.js"></script> -->
<script>
window.addEventListener(`load`, (event) => {
console.log(`page loaded ✅`);
fetch(`http://localhost:3000/img`)
.then(res => res.json())
.then(json => {
console.log(`json`, json);
const img = document.querySelector(`#img`);
// img.src = `data:image/png;base64,${json.data}`;
img.src = json.data;
});
});
</script>
</body>
</html>
client.js
window.addEventListener(`load`, (event) => {
console.log(`page loaded ✅`);
fetch(`http://localhost:3000/img`)
.then(res => res.json())
.then(json => {
console.log(`json`, json);
const img = document.querySelector(`#img`);
// img.src = `data:image/png;base64,${json.data}`;
img.src = json.data;
});
});
document.addEventListener(`DOMContentLoad`, (event) => {
console.log(`DOM fully loaded and parsed ✅`);
if (!!window.EventSource) {
const img = document.querySelector(`#img`);
// const source = new EventSource('/img');
const source = new EventSource('http://localhost:3000/img');
source.onopen = (e) => {
console.log(`✅ Connection to server opened.`, e);
};
source.message = (e) => {
const data = e.data;
console.log(`🚀 data =`, data)
// img.src = `data:image/jpg;base64,${data}`;
// img.src = `data:image/png;base64,${data}`;
img.src = `${data}`;
};
// source.addEventListener(`message`, (e) => {
// const data = e.data;
// console.log(`data =`, data)
// img.src = `data:image/png;base64,${data}`;
// }, false);
source.onerror = (err) => {
console.log(`❌ EventSource failed.`, err);
setTimeout(() => {
console.log(`⚠️ After 3 seconds, auto close connection!`);
source.close();
}, 3000);
};
} else {
console.log(`Your browser doesn't support SSE ❌`);
}
});
custom event type
server.js
app.get('/sse', (req, res) => {
res.writeHead(200, {
// 'Content-Type': 'image/jpg',
// 'Content-Type': 'image/png',
// 'Content-Type': 'application/json',
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
// 'CharacterEncoding': 'UTF-8',
// 'Accept-Encoding': 'UTF-8',
});
// response.setContentType("text/event-stream");
// response.setCharacterEncoding("UTF-8");
// const data = convertImageToBase64URL("./public/test.png");
// console.log(`SSE`, data.slice(0, 100));
// res.write(data);
let i = 0;
let uid = setInterval(() => {
console.log(`i`, i);
if(i < 10) {
i++;
const data = convertImageToBase64URL("./public/test.png");
console.log(`SSE ${i}`, data.slice(0, 100));
// ❌
// res.write(data);
// ✅ 使用 \n\n 换行符号,标识 stream 结束 ❓
// event type `message` \n
// event data `data` \n\n
// res.write(`event: message\n`);
// custom event type `custom_message`\n ✅
res.write(`event: custom_event_message\n`);
res.write(`data: ${data}\n\n`);
} else {
clearInterval(uid);
res.end();
}
}, 3000);
});
// http://localhost:3000/sse
client.js
window.addEventListener(`load`, (e) => {
console.log(`page loaded ✅`);
if (!!window.EventSource) {
const img = document.querySelector(`#sse`);
const source = new EventSource('http://localhost:3000/sse');
source.onopen = (event) => {
console.log(`✅ Connection to server opened.`, event);
};
// ✅ default event type `message` 可以使用 `onmessage` / addEventListener(`message`
// source.onmessage = (event) => {
// console.log(`event`, event);
// const type = event.type;
// console.log(`event.type`, type);
// const data = event.data;
// console.log(`🚀 event.data =`, data)
// // img.src = `data:image/jpg;base64,${data}`;
// // img.src = `data:image/png;base64,${data}`;
// img.src = `${data}`;
// };
source.addEventListener(`message`, (event) => {
console.log(`event`, event);
const type = event.type;
console.log(`event.type`, type);
const data = event.data;
console.log(`🚀 event.data =`, data)
// img.src = `data:image/jpg;base64,${data}`;
// img.src = `data:image/png;base64,${data}`;
img.src = `${data}`;
});
// ❌ custom event message 不可以使用 `onmessage`
// source.oncustom_event_message = (event) => {
// ✅ custom event message 只可以使用 addEventListener(`custom_event_message`
source.addEventListener(`custom_event_message`, (event) => {
console.log(`event`, event);
const type = event.type;
console.log(`event.type`, type);
const data = event.data;
console.log(`🚀 event.data =`, data)
// img.src = `data:image/jpg;base64,${data}`;
// img.src = `data:image/png;base64,${data}`;
img.src = `${data}`;
});
source.onerror = (err) => {
console.log(`❌ EventSource failed.`, err);
// setTimeout(() => {
// console.log(`⚠️ After 3 seconds, auto close connection!`);
// source.close();
// }, 3000);
};
} else {
console.log(`Your browser doesn't support SSE ❌`);
}
});
(🐞 反爬虫测试!打击盗版⚠️)如果你看到这个信息, 说明这是一篇剽窃的文章,请访问 https://www.cnblogs.com/xgqfrms/ 查看原创文章!
Node.js image generator
https://www.npmjs.com/package/js-image-generator
https://www.npmjs.com/package/pureimage
Node.js convert image
to base64
string
https://www.npmjs.com/package/image-to-base64
Node.js
Buffer.from
All In One
https://www.cnblogs.com/xgqfrms/p/17357737.html
refs
How to fix
EventSource
onmessage not working in JavaScript All In One
https://www.cnblogs.com/xgqfrms/p/17783689.html
https://stackoverflow.com/questions/77341435/nodejs-sending-image-files-using-sse/77342298#77342298
https://stackoverflow.com/questions/5195452/websockets-vs-server-sent-events-eventsource/5326159
res.end();
©xgqfrms 2012-2021
www.cnblogs.com/xgqfrms 发布文章使用:只允许注册用户才可以访问!
原创文章,版权所有©️xgqfrms, 禁止转载 🈲️,侵权必究⚠️!
本文首发于博客园,作者:xgqfrms,原文链接:https://www.cnblogs.com/xgqfrms/p/17781678.html
未经授权禁止转载,违者必究!